In this article, we will demonstrate getting started with xUnit.net, showing you how to write and run your first set of unit tests.
Note: The examples were done with xUnit.net v2 2.4.1 and Visual Studio 2019. The version numbers, paths, and Visual Studio UI may differ for you, depending on which version you're using.
Start Visual Studio, which will bring you to the start splash screen. Under "Get Started", click "Create a new project". This will bring you to the first step of the new project wizard, where you pick your project type:
In the drop down boxes, chooses your language (C#), your platform (All platforms), and your project type (Test). Scroll through the list if necessary until you find the item titled "xUnit Test Project (.NET Core)". Select it, then click "Next".
We're picking .NET Core even though we're planning to make a .NET Framework test project, because Visual Studio doesn't contain a test project template for xUnit.net for .NET Framework. We'll fix that in just a moment.
This leads you to the second part of the new project wizard:
Type a name into the "Project name" box (like "MyFirstUnitTests"). Click "Create".
After a moment, Visual Studio will launch with your newly created project.
Find the project in the Solution Explorer (it will be titled "MyFirstUnitTests"), right click it, then click "Edit Project File". This will launch the text editor for your project file. It should look something like this:
We need to make one quick change: use a target framework that indicates .NET Framework
support. For example, if you want to support .NET Framework 4.8, change the
TargetFramework
element like so:
Let's quickly review what's in this project file:
TargetFramework
specifies the target framework for your test project. We've
already changed this to net48
for .NET Framework 4.8. Later in this article,
we will discuss running tests against multiple target frameworks.
IsPackable
is here, though it is redundant (unit test projects cannot be packed
by default). You can safely remove this line if you wish.
xunit
package brings in three child packages which include functionality
that most developers want: xunit.core
(the testing framework itself),
xunit.assert
(the library which contains the Assert
class),
and xunit.analyzers
(which enables Roslyn analyzers to detect common issues
with unit tests and xUnit.net extensibility).
xunit.runner.visualstudio
and Microsoft.NET.Test.Sdk
are required for being able to run your test project inside Visual Studio as well as with
dotnet test
.
coverlet.collector
package allows collecting code coverage. If you don't
intend to collect code coverage, you should remove this package reference.
A single empty unit test was also generated into UnitTest1.cs
:
Let's make sure everything builds. Choose Build > Build Solution
from the
main menu. Your project should build without issue, as shown in the output window:
Build started... 1>------ Build started: Project: MyFirstUnitTests, Configuration: Debug Any CPU ------ 1>MyFirstUnitTests -> C:\Dev\MyFirstUnitTests\bin\Debug\net48\MyFirstUnitTests.dll ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Test Explorer is the name of the window that lets you browse and run your tests from within
Visual Studio. Open it by choosing Test > Test Explorer
from the main menu.
You should be greeted with a window that contains a hierarchy of the tests in your project,
which should look something like this:
The toolbar of Test Explorer has buttons in several groups:
The main window of Test Explorer is split into two panes:
Click the left-most button on the Test Explorer toolbar (it looks like a double green arrow, titled "Run All Tests In View". This will run the single empty test, and the result should be success:
Now that we've ensured everything is working, it's time to write our first real tests.
Edit UnitTest1.cs
and replace the default file contents with this:
Now let's go run the tests again and see what happens:
We purposefully wrote both a passing and failing test, and we can see that the results reflect that. By clicking on the failed test, we can see a link both to the top of the unit test (at line 14), but also the failure message (we expected 5 but got 4) as well as a link to the exact line where the failure occurred (line 16).
When you edit the source file, also take note of the fact that CodeLens decorations show up which indicate not only test status (passed/failed) on the test themselves, but also on functions that are called by the code, indicating how often the code is called in tests, and a count of which of those tests have passed or failed:
Now that we've gotten your first unit tests to run, let's introduce one more way to write tests: using theories.
You may have wondered why your first unit tests use an attribute named
[Fact]
rather than one with a more traditional name like Test.
xUnit.net includes support for two different major types of unit tests:
facts and theories. When describing the difference between facts and theories,
we like to say:
Facts are tests which are always true. They test invariant conditions.
Theories are tests which are only true for a particular set of data.
A good example of this is testing numeric algorithms. Let's say you want to test an algorithm which determines whether a number is odd or not. If you're writing the positive-side tests (odd numbers), then feeding even numbers into the test would cause it fail, and not because the test or algorithm is wrong.
Let's add a theory to our existing facts (including a bit of bad data, so we can see it fail):
This time when we run our tests, we see a second failure, for our theory that was given 6:
Although we've only written 3 test methods, the test runner actually ran 5 tests; that's because each theory with its data set is a separate test. Note also that the runner tells you exactly which set of data failed, because it includes the parameter values in the name of the test. The Test Explorer UI even shows a new level in the tree, as each row of data becomes a test result underneath its test method.
Sometimes, you want to write tests and ensure they run against several target
application platforms. The xUnit.net test runner that we've been using supports
.NET Core 1.0 or later, .NET 5.0 or later, and .NET Framework 4.5.2 or later.
With a single test project, we can have our tests run against multiple target
frameworks. Open the .csproj
file and make the following change.
Change TargetFramework
:
To TargetFrameworks
:
When you change a project file from TargetFramework
to
TargetFrameworks
(or back), Visual Studio might show you a yellow
"alert bar" which indicates that you have to reload the project for your changes
to take effect. It's best to make this kind of change from a clean environment
with no dirty text editors, to prevent the possibility of losing any changes.
Test Explorer supports any combination of .NET Core (including .NET 5+)
and .NET Framework targets. You can even include multiple versions of the same
target framework (for example, it's legal to have something like
<TargetFrameworks>net452;net461;net48;netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
).
Application authors will typically only use a single target framework, related to
the target framework the application is intended to run on. Library authors are more
likely to use several target frameworks, to ensure their tests run successfully on
all supported target frameworks.
The Test Explorer tree view will now show your test project multiple times, once for each target framework. You can run individual tests from individual frameworks, or you can simply run all tests for all frameworks.