code4it-dev / blog-comments

https://www.code4it.dev/
1 stars 0 forks source link

blog/code-coverage-must-not-be-the-target/ #67

Open utterances-bot opened 3 months ago

utterances-bot commented 3 months ago

Why reaching 100% Code Coverage must NOT be your testing goal (with examples in C#) | Code4IT

Code4IT - a blog for .NET enthusiasts, Azure lovers, and Backend developers

https://www.code4it.dev/blog/code-coverage-must-not-be-the-target/

tomap commented 3 months ago

Excluding controllers is probably not the best example because this can be tested via intégration tests / test server But sometimes you don't have a mocked db, so you have to mock the whole repository.

jsnape commented 3 months ago

I wrote about ExcludeFromCodeCoverage recently as its so tempting to hide things just to reach an artificial goal. Its particularly difficult to cover some of the hidden compiler code generated from yield statements.

bantling commented 3 months ago

You're only considering C# in your arguments. Some languages like Go are far more practical for getting 100% coverage. That's because in Go there is one criteria: a line is covered if it is executed.

If you have an if statement with 4 boolean conditions, there are 5 possibilities:

If you have a for loop with a test, there are two possibilities:

Sounds like C# wants you to test all 5 if statement possibilities, and both loop possibilities to get 100%, just like EclEmma in Java. But Go only requires any one case to consider the line fully covered.

This makes it much easier to get 100% coverage in Go. It is also feasible to go beyond 100% coverage to achieve domain coverage - actually testing the problem itself.

Say you're making a JSON parser. One problem is that you can have \uHHHH sequences that are UTF-16. But since Unicode code points can be up to 24 bits in size, UTF-16 sometimes requires two 16 bit values - a high surrogate followed by a low surrogate. To get domain coverage, you would need to test:

Once you have a unit test for handling a single \u sequence, handling the remaining cases will provide very little extra line coverage, but significantly improve the domain coverage. After all, if you have a JSON string with an incorrect surrogate sequence, it could take a very long time for someone to figure out why the string looks so weird - but if the parser gives a specific error about it, they will understand immediately what is wrong with the string.

I would say focus on as much domain coverage as is feasible (not all situations are as relatively simple as JSON parsing). Use whatever percentage of unit testing the language makes feasible - for C# and Java, 80% is generally considered fine, for Go 90% should be ok in most cases.

If you want a high quality library, you can increase the unit testing coverage, but in my view you should always focus more on getting the domain covered. Increasing domain coverage:

tomap commented 3 months ago

That's the difference between Line coverage and Branch coverage if(condition) => two branches to have 100% branch coverage, you'll need to test with condition == true AND condition == false

to have 100% line coverage, you'll need to test with only one of the conditions

check this software: https://github.com/danielpalme/ReportGenerator?tab=readme-ov-file#screenshots where linecoverage > branchcoverage