Types almost 100% tested should be 100% tested

Rule ND1604 Code Coverage

Runs only when coverage data is imported.

Covering the last few percents of a class 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. 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>Types almost 100% tested should be 100% tested</Name>
// <Id>ND1604:TypesAlmost100PercentTestedShouldBe100PercentTested</Id>

warnif count > 0
from t in JustMyCode.Types where 
  t.PercentageCoverage >= 95 && 
  t.PercentageCoverage <= 99 &&
 !t.IsGeneratedByCompiler

  let methodsCulprit = t.Methods.Where(m => m.PercentageCoverage < 100)

  orderby t.NbLinesOfCode descending , 
           t.NbLinesOfCodeNotCovered ,
           t.PercentageCoverage
select new { 
   t, 
   t.PercentageCoverage,
   t.NbLinesOfCode, 
   t.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 = t.NbLinesOfCodeNotCovered.Linear(1,2, 20,20).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 class 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. *Hard-to-test code* signals a
// design needing refactoring.
//</HowToFix>

Code Coverage: all 15 items