Namespaces almost 100% tested should be 100% tested

Rule ND1605 Code Coverage

Runs only when coverage data is imported.

Covering the last few percents of a namespace's classes is as hard as the first 90%, so teams often settle for 90%. But untestable code usually means poorly written, error prone code: worth covering because most tricky bugs might come from this small portion of hard-to-test code. Not all classes need 100% coverage (e.g. UI), but most of the application logic should live in easy-to-test classes 100% covered.

Severity is High: such situation is bug-prone.

How to fix

Write more unit-tests for uncovered code in the namespace. Hard-to-test code signals a design needing refactoring.

CQLinq source

This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.

// <Name>Namespaces almost 100% tested should be 100% tested</Name>
// <Id>ND1605:NamespacesAlmost100PercentTestedShouldBe100PercentTested</Id>

warnif count > 0
from n in JustMyCode.Namespaces where 
  n.PercentageCoverage >= 95 && 
  n.PercentageCoverage <= 99 

  let methodsCulprit = n.ChildMethods.Where(m => m.PercentageCoverage < 100)

  orderby n.NbLinesOfCode descending , 
           n.NbLinesOfCodeNotCovered ,
           n.PercentageCoverage
select new { 
   n, 
   n.PercentageCoverage, 
   n.NbLinesOfCode, 
   n.NbLinesOfCodeNotCovered, 
   methodsCulprit,

   // Simplistic Debt estimation, because the effort to write tests for a type not 100% tested
   // is already estimated properly with the rule "Code should be tested".
   Debt = n.NbLinesOfCodeNotCovered.Linear(1,2, 50,60).ToMinutes().ToDebt(),

   Severity = Severity.High
} 

//<Expl>
// The *{0}* is {1}% covered by test. There are only {3} statement{3?:s} on {2} that remain untested.
// {3?This:These few} *hard-to-test* statement{3?:s} may indicate *poor design* 
// and potential *error-prone* behavior.
// Write test and achieve 100% coverage helps ensure that rules 
// *Types that used to be 100% covered by tests should still be 100% covered* 
// can identify any coverage regressions that could potentially introduce bugs.
//</Expl>

//<Desc>
// Runs only when coverage data is imported.
//
// Covering the last few percents of a namespace's classes is as hard as the
// first 90%, so teams often settle for 90%. But *untestable code* usually
// means *poorly written*, *error prone* code: worth covering **because most
// tricky bugs might come from this small portion of hard-to-test code**. Not
// all classes need 100% coverage (e.g. UI), but most of the application
// logic should live in *easy-to-test classes* 100% covered.
//
// Severity is **High**: such situation is *bug-prone*.
//</Desc>

//<HowToFix>
// Write more unit-tests for uncovered code in the namespace. *Hard-to-test
// code* signals a design needing refactoring.
//</HowToFix>

Code Coverage: all 15 items