· 5 min read
What’s New in xUnit v3? Essential Features to Supercharge Your Tests
Learn about the new features and improvements in xUnit v3.
xUnit still remains one of the most popular unit testing frameworks in the .NET ecosystem, if not the most popular. The xUnit team has been working hard to bring new features and improvements to the framework. The upcoming xUnit v3 is no exception and it is still in preview at the time of writing this post.
In this post, I’ll cover some of the new features and improvements coming in xUnit v3 which I found interesting. Note that these features are subject to change as the framework is still in preview.
In-process Console Runner
xUnit v3, now comes with an in-process console runner that allows you to build standalone executables directly from your test projects. To use the in-process console runner, you need to just add OutputType
properties to your project file. Also, you can skip using the regular test SDK Microsoft.NET.Test.Sdk
while using the in-process console runner.
Here is an example project file that can be used with the in-process console runner:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType> <!-- Use Exe output type -->
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3" Version="0.6.0-pre.7" /> <!-- Use xUnit v3 package -->
</ItemGroup>
</Project>
If you still want to use the VSTest Runner, you still need to use the Microsoft.NET.Test.Sdk
project SDK and include the xunit.runner.visualstudio
package.
Here is an example project file that can be used with the VSTest Runner:
<Project Sdk="Microsoft.NET.Test.Sdk"> <!-- Use Microsoft.NET.Test.Sdk -->
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3" Version="0.6.0-pre.7" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0-pre.49" /> <!-- VSTest Runner -->
</ItemGroup>
</Project>
Assembly-Level Fixtures
The Assembly-Level Fixture is a new feature in xUnit v3 that allows you to share the same fixture instance across all test classes in the assembly. This can be done using the AssemblyFixture
attribute. Assembly-Level Fixtures are really a step up from Collection Fixtures, which require an extra class to carry the CollectionDefinition
attribute.
Here is an example of how to use the Assembly-Level Fixture:
[assembly: AssemblyFixture(typeof(MyFixture))] // Mark the fixture class as AssemblyFixture
public class MyFixture : IDisposable
{
public MyFixture()
{
// Initialize the fixture
}
public void Dispose()
{
// Cleanup the fixture
}
}
public class MyTestClass1(MyFixture fixture) // Inject the fixture into the test class
{
[Fact]
public void Test1()
{
// Use the fixture
}
}
Once you mark the fixture class with the AssemblyFixture
attribute, the fixture will be created before any tests are run and disposed of after all tests are run. Also the fixture instance can be injected into any test class in the assembly.
Test Pipeline Startup
Sometimes you need to run some code early in the test run, even before the assembly-level fixtures are created. To run things even earlier than assembly-level fixtures, you can use the new ITestPipelineStartup
interface and new TestPipelineStartup
attribute. They allow you to run any code before any tests are discovered or run. This can be useful for setting up global test environment settings. They also provide a way to run any cleanup code after all tests are run.
Below is an example of how to use the Test Pipeline Startup:
[assembly: TestPipelineStartup(typeof(MyTestPipelineStartup))] // Mark the pipeline class as TestPipelineStartup
public class MyTestPipelineStartup : ITestPipelineStartup
{
public async Task StartAsync()
{
// Setup the pipeline
}
public async Task StopAsync()
{
// Cleanup the pipeline
}
}
Note that you can have only one Pipeline Startup class per assembly. The StartAsync
method is called before any tests are discovered or run, and the StopAsync
method is called after all tests are run.
Support for Console
, Debug
, and Trace
Output
xUnit v3 now supports capturing output from Console
, Debug
, and Trace
output. This can be useful for debugging tests or capturing logs. You can capture the output using the ITestOutputHelper
interface. Currently, they are disabled by default for backward compatibility reasons. You can enable by using assembly-level attributes like CaptureConsole
and CaptureTrace
.
[assembly: CaptureConsole] // Capture Console output
[assembly: CaptureTrace] // Capture Debug and Trace output
Support for Microsoft Testing Platform
xUnit v3 also supports the Microsoft Testing Platform (MSTest) which means you can run xUnit tests using the MSTest test runner. To switch using the MSTest test runner, you need to add the following property to your project file:
<PropertyGroup>
<UseMicrosoftTestingPlatform>true</UseMicrosoftTestingPlatform>
</PropertyGroup>
Once you toggle the UseMicrosoftTestingPlatform
property, the test runner will use the MSTest test runner instead of the xUnit test runner and you’ll find the commandline experience is more similar to what you see in MSTest or TUnit.
Just like xUnit v3, Microsoft Testing Platform also supports standalone executables while offering improved performance and NuGet-based extensibility model.
Explicit Tests
While writing tests, you can now mark tests as Explicit
by adding Explicit = true
to the Fact
or Theory
attribute. This can be useful when you want to exclude certain tests from the test run.
[Fact(Explicit = true)]
public void IntegrationTest1()
{
// Test code
}
[Theory(Explicit = true)]
[InlineData(1)]
[InlineData(2)]
public void IntegrationTest2(int value)
{
// Test code
}
This feature can be particularly handy when you want to exclude integration tests from general test runs.
Wrapping Up
These are only handful of the new features and improvements coming in xUnit v3. The majority of the focus in v3 is the fundamental changes to the core framework and the test runners, to make it more extensible and performant. More importantly, the runner utilities has a major overhaul to make it more flexible and easier to use. Besides, some of the reflection-based abstractions have been removed from the core framework. With this, I am also hoping for a full NativeAOT support in the future releases.
Although xUnit v3 is still in preview, you can try it out by installing the xunit.v3
package from NuGet or use their new v3 templates. Note that if you are having existing v2 projects, the migration path to v3 may not be straightforward and you may need to make some changes to your test projects. For more information, you can check out their migration guide here.