Testing is the middle name of every serious software developer. But there is still a bit more to it than standard testing with the xUnit framework. With additional analysis of the code coverage, you can raise the quality of your unit tests to a higher level. The effort is low, because .NET already has the necessary tools on board.
You get a better feel for your coding because:
- You will find untested code.
- You will find unreachable (dead) code.
- You will identify missing (not implemented) functionality more easily.
- You will measure the complexity of your code.
The following code block shows how to create an xUnit test project and add the appropriate test data collector to your project. You also have to install a global report generator once.
# create test project
dotnet new xunit -n CodeCoverageTesting.Units.Test
# add test data collector
cd CodeCoverageTesting.Units.Test
dotnet add package coverlet.collector
# install global reportgenerator
dotnet tool install -g dotnet-reportgenerator-globaltool
You implement your tests using the well-known xUnit method. If you need initial help, you will find many examples on GitHub in the xUnit repository. For the first example test you write yourself an AND logic to be tested and save it in a separate .NET class library project.
namespace CodeCoverageTesting.Units.Logical;
public static class LogicalGate
{
public static bool And(bool a, bool b)
{
if (a != true) return false;
return b == true;
}
}
Then you implement a first test case in the previously created test project. For the complete test of the AND logic, you can write three more test cases using the method shown above.
using CodeCoverageTesting.Units.Logical;
using Xunit;
namespace CodeCoverageTesting.Units.Test.TestCases;
public class LogicalGateTest
{
[Fact]
public void Should_BeFalse()
{
Assert.False(LogicalGate.And(/*a*/ false, /*b*/ true));
}
}
The following code block shows you how you can run your tests by script. You create a shell script for this in the project directory next to the * .csproj project file.
#!/bin/sh
dotnet test --collect:"XPlat Code Coverage"
You then start the script from your shell. Make sure to make your script executable beforehand.
./test_code_coverage.sh
After the test execution, your project directory could look like this.
.
├── TestCases
├── TestResults
│ └── 390ff9f7-6d5f-4d38-ab6b-84e74b5a3d76
│ └── coverage.cobertura.xml
└── test_code_coverage.sh
How to generate a report from the collected test data can be seen in the following code block. The best thing to do is to write a short shell script here as well.
#!/bin/sh
GUID="$1"
EXPORT_DIR="./TestResults/${GUID}"
reportgenerator "-reports:${EXPORT_DIR}/coverage.cobertura.xml" "-targetdir:${EXPORT_DIR}/coveragereport" -reporttypes:Html
You then start generating the report (including specifying the guide for the test data) as follows.
./test_report.sh 390ff9f7-6d5f-4d38-ab6b-84e74b5a3d76
After the test execution and report generation, your project directory could look like this.
.
├── TestCases
├── TestResults
│ └── 390ff9f7-6d5f-4d38-ab6b-84e74b5a3d76
│ ├── coverage.cobertura.xml
│ └── coveragereport
├── test_code_coverage.sh
└── test_report.sh
In the coveragereport directory you will now find an HTML report that you can open via your browser.
The test report provides you with information on the coverage and cyclomatic complexity (McCabe metric) of your tested code. You can use groupings and filters to analyze your code from the namespace level down to the method level. Here you can get a first look at the test report for the example discussed.
With the test case shown, you will achieve a line coverage of 75% and a branch coverage of 50%. All green lines and branches are completely covered by your testing. The yellow and red lines or branches, on the other hand, have only been tested partially or not at all, you can still improve here. According to McCabe, your code has a low cyclomatic complexity of 2 and is harmless.
As already mentioned above, you could achieve coverage of 100% line and branch coverage through further targeted test cases. Just give it a try!
Hopefully this simple example will show you what additional analysis options code coverage testing can offer you. It is of course now up to you to decide what code coverage is required for your testing. Once you have made your first experiences, it is best to define a sufficient end criterion for your code coverage tests in advance.
You can find the complete code in this GitHub repository.
Happy Testing!