No repository lets contributors add code that does not contain associated tests with it. In my own experience, I have collaborated on the Flutter8 repository on GitHub. Flutter developers had added checks to verify whether I added tests to verify my code. Similarly, every other project has some tests that verify the overall quality of the product after your code gets merged—and notifies is something fails. Now that our application can sum two integers and return the result as an integer. We need to make sure that the code performs as it is expected to perform.
On .NET Core we have several library options available to write testing scripts for our projects. Although we do discuss a broader set of tests throughout the book, for now, we will only focus on the unit testing approach for .NET Core. I will walk you through the usage of the XUnit library and a few of its options to create the tests that can help you maintain a stable version of your product.
To add testing to the project, you need to create a new project. We will again use the dotnet CLI and create a new project of type XUnit and then add the reference to the previous project.
$ mkdir project.xunit Directory: <path-removed>
8 Flutter is a cross-platform mobile and desktop application development framework by Google.
Mode LastWriteTime Length Name ---- --- --- ----
d--- 11/10/2019 9:10 PM project.xunit
$ cd project.xunit
$ dotnet new xunit
The template "xUnit Test Project" was created successfully.
Processing post-creation actions...
Running 'dotnet restore' on <your-path>\project.xunit\project.
xunit.csproj...
Restore completed in 1.33 sec for <your-path>\project.xunit\
project.xunit.csproj.
Restore succeeded.
$ dotnet add reference ../project/Project.csproj
Reference `..\project\Project.csproj` added to the project.
Remember, lines starting with $ are the commands to be executed, and other lines are the potential output for these commands.
Now we have connected our projects and have a sample test file created. We can go ahead and write the sample test cases to verify the functionality of our product. Open the UnitTest1.cs9 file and modify the internal code by pasting this:
using System;
using Xunit;
using Project;
namespace project.xunit {
public class MathTests {
[Fact]
public void Add_2_Plus_2_Equals_4() {
// Arrange
// Nothing to arrange, our class has static member.
// Act
int result = Arithmetic.Add(2, 2);
// Assert
Assert.Equal(4, result);
} } }
This is a very basic unit test and verifies that our code returns 4
for the operands 2 and 2. Inside this code, we have some unique keywords.
A Fact is the unit test in the project. Your IDE and dotnet tool can identify the types that have these attributes applied and run tests on these
functions. A unit test follows “Three A” approach:
• Arrange
• Act
• Assert
We create the variables and set up sources during the Arrange step. We perform some actions or Act on the variables and data sources created in the Arrange step. Lastly, we put some assertions or Assert on the results of the values to verify that functions return correct outputs. We have used the same approach here, but since our class had a static member function,10 we do not need to create the variables. Then we write the code to call the
10 If our code had an instance function, then we would create a new instance in Arrange step. See the code on Page 7.
function with our test cases, 2 and 2. Lastly, we put an assertion to verify that our code indeed returns the correct value, which in this case would be 4.
We can now run a dotnet test to run the tests in this project—currently, we only have one test—and see if they pass.
$ dotnet test
Test run for <path>\project.xunit\bin\Debug\netcoreapp3.0\
sample.xunit.dll(.NETCoreApp,Version=v3.0)
Microsoft (R) Test Execution Command Line Tool Version 16.3.0 Copyright (c) Microsoft Corporation. All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Test Run Successful.
Total tests: 1 Passed: 1
Total time: 2.7898 Seconds
Since our package only had a single test, it printed one test found in the console and ran it. This verifies that our project works as expected. We can use the dotnet test CLI in our DevOps pipelines to verify the quality of the code that comes from contributors. If there is a minor bug in our code, the test will fail, ultimately causing the build to fail and the DevOps cycle to stop. This can also alert the team to review the code and fix any problems before accepting the changes.
When it comes to testing the packages, IDEs sometimes have an improved developer experience. Visual Studio, for example, contains Live Unit Testing that provides a real-time result for unit tests and shows which areas of the code might have bugs. If you created the project with Visual Studio, you would see the following result (in GUI; see Figure 2-4 as it shows 1/1 passing label on the function) after running a dotnet test.
The Live Unit Testing feature needs to be started manually and then it can automatically run the tests on your code and show results in real-time as you write the code and modify the code/test (see Figure 2-5).
Figure 2-5. You can find the option under Test ➤ Live Unit Testing ➤ Start Figure 2-4. Visual Studio shows the overall references that a class and its members have, and the number of tests for the members and how many passes/fail
This would yield an extra field in the gutter area of Visual Studio and show whether the code is fine or not. Since we know our tests pass, we can see the same result in Visual Studio, as shown in Figure 2-6.
You can change the test sets to see how they fail in real-time. Now we rewrite the code and change the assertion we have:
// Assert
Assert.Equal(5, result);
As soon as we change the line, Visual Studio Live Unit Testing reruns the tests and verifies the package for the changes made (see Figure 2-7).
Figure 2-6. Two ticks in the gutter show the lines of code where the tests pass
Figure 2-7. Change the code to assert the result to be equal to the
Once the test fails, your code will show the icons to demonstrate that the tests have failed and that they need to be fixed (see Figure 2-8).
To see how the package references and recursive build works, run dotnet build in the test directory.
$ dotnet build
Microsoft (R) Build Engine version 16.3.0+0f4c62fea for .NET Core Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 42.88 ms for <path>\project\Project.csproj.
Restore completed in 71.24 ms for <path>\project.xunit\
project.xunit.csproj.
Project -> <path>\project\bin\Debug\netcoreapp3.0\Project.dll project.xunit -> <path>\project.xunit\bin\Debug\
netcoreapp3.0\sample.xunit.dll Build succeeded.
0 Warning(s) 0 Error(s)
Time Elapsed 00:00:05.17
This gives us a hint as to how dotnet CLI builds dependency projects and prepares them to be linked to our projects.
Figure 2-8. Functions show a red x, demonstrating the tests failure