Introduction to xUnit
Learn how to set up xUnit tests.
We'll cover the following
In this lesson, we’ll learn how to set up a basic automated test using xUnit. We’ll do so with the help of the following interactive playground:
namespace MainApp; public class Calculator { public int MultiplyByTwo(int value) { return value * 2; } }
In this setup, we have the main application located in the MainApp
folder. This is a basic console application. Inside it, we have the Calculator.cs
file. On line 5 of this file, we have the following method, which multiplies an integer number passed to it by two:
public int MultiplyByTwo(int value){return value * 2;}
We will write a test that validates this behavior.
Adding xUnit dependencies
Our executable, which contains the xUnit tests, is represented by the MainApp.Tests
project. We use the same naming convention that’s often used in real-life projects. We create tests for a specific library or executable, which is MainApp
in our case. Then, we use the same name in our test project but add the .Tests
suffix to the name.
If we open the MainApp.Tests.csproj
file inside this folder, we see on lines 13–22 the following necessary NuGet dependencies:
Microsoft.NET.Test.Sdk
: This allows the tests to be executed by .NET.xunit
: This contains the core xUnit dependencies.xunit.runner.visualstudio
: This allows xUnit tests to be recognizable by the Test Explorer in Visual Studio .IDE An integrated development environment is a software that allows developers to write code, debug it, and build their application. coverlet.collector
: This allows us to collect code coverage metrics.
Then, once we add all the necessary dependencies, we need to add a reference to the project that we want to test. We do so on line 26 of the MainApp.Tests.csproj
file.
Writing xUnit tests
Before using xUnit, we must add the Xunit
namespace reference. We do that globally in the MainApp.Tests
project. We reference it with the global using
keywords in the Usings.cs
file.
Our test can be found in the CalculatorTests.cs
file. Here, we use a commonly accepted naming convention once again. Because we’re testing public methods in a specific class, we’ve given our test class the same name as the class we test, appending the Tests
suffix to it.
If we open this file, we see that it has a single public method marked with the Fact
attribute, which we can find on line 5. This is the attribute that xUnit uses to mark test methods. The test runner recognizes this method as a test it can execute. The method itself appears as follows:
public void MultiplyByTwo_CanMultiply(){Calculator calculator = new();int result = calculator.MultiplyByTwo(2);Assert.Equal(4, result );}
In this example, we give our method a descriptive name to explain what we validate in the test using the following method:
{name of the method under test}_{can perform an action}
This is also a fairly common naming convention used for naming test methods. In it, we first provide the name of the method we test. Then, we add an underscore followed by a description of the capability we validate. In our case, we test the MultiplyByTwo
method and validate that this method can do the multiplication.
On line 3 of the snippet above, we create an instance of the Calculator
class. Then, we call the MultiplyByTwo()
method and obtain the result. On line 5, we use the Assert
class supplied by the testing framework to verify that the result matches the expected value, which in our case is 4
. The test passes if the actual value matches the expected value. The test fails if the value is different or if an exception is thrown during the execution.
Examining the test output
We can see how the test works by clicking the “Run” button in the playground at the beginning of the lesson. Doing this builds the project, and the playground executes the dotnet test
command line interface (CLI) command. The output of this command shows how many tests are executed and if all of them pass. In our case, it looks similar to the following:
Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms
Here is what the output represents:
Overall status: This is either
Passed!
orFailed!
. It’s considered a failure if any of the tests fail, otherwise it passes.Failed: This is the count of failed tests.
Passed: This is the count of passed tests.
Skipped: This is the count of the test methods that didn’t run because they were configured to be excluded.
Total: This is the total number of tests executed.
Duration: This is the total duration of the test execution.
Test output for failing tests
If we want to see what the output looks like when a test fails, we can add the following method to the CalculatorTests.cs
file:
[Fact]public void Fail(){Calculator calculator = new();int result = calculator.MultiplyByTwo(2);Assert.Equal(3, result );}
This fails because its assertion statement is deliberately configured to expect the wrong value (3
instead of 4
). If we execute this now, we should see output similar to the following:
Failed! - Failed: 1, Passed: 1, Skipped: 0, Total: 2, Duration: 65 ms
We also see the error telling us which specific test failed.