xUnit.net: Global setup + teardown?
As far as I know, xUnit does not have a global initialization/teardown extension point. However, it is easy to create one. Just create a base test class that implements IDisposable
and do your initialization in the constructor and your teardown in the IDisposable.Dispose
method. This would look like this:
public abstract class TestsBase : IDisposable
{
protected TestsBase()
{
// Do "global" initialization here; Called before every test method.
}
public void Dispose()
{
// Do "global" teardown here; Called after every test method.
}
}
public class DummyTests : TestsBase
{
// Add test methods
}
However, the base class setup and teardown code will be executed for each call. This might not be what you want, as it is not very efficient. A more optimized version would use the IClassFixture<T>
interface to ensure that the global initialization/teardown functionality is only called once. For this version, you don't extends a base class from your test class but implement the IClassFixture<T>
interface where T
refers to your fixture class:
using Xunit;
public class TestsFixture : IDisposable
{
public TestsFixture ()
{
// Do "global" initialization here; Only called once.
}
public void Dispose()
{
// Do "global" teardown here; Only called once.
}
}
public class DummyTests : IClassFixture<TestsFixture>
{
public DummyTests(TestsFixture data)
{
}
}
This will result in the constructor of TestsFixture
only being run once
for every class under test. It thus depends on what you want exactly to choose between the two methods.
How to perform global setup/teardown in xUnit and run tests in parallel?
NUnit supports this scenario. For global setup, create a class in one of your root namespaces and add the [SetupFixture] attribute to it. Then add a [OneTimeSetUp] method to that class. This method will get run once for all tests in that namespace and in child namespaces. This allows you to have additional namespace specific onetime setups.
[SetUpFixture]
public class MySetUpClass
{
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
// ...
}
[OneTimeTearDown]
public void RunAfterAnyTests()
{
// ...
}
}
Then to run your tests in parallel, add the [Parallelizable] attribute at the assembly level with the ParallelScope.All
. If you have tests that should not be run in parallel with others, you can use the NonParallelizable
attribute at lower levels.
[assembly: Parallelizable(ParallelScope.All)]
Running test methods in parallel in NUnit is supported in NUnit 3.7 and later. Prior to that, it only supported running test classes in parallel. I would recommend starting any project with the most recent version of NUnit to take advantages of bug fixes, new features and improvements.
run initialisation and teardown code once while outputting in the constructor and destructor
The documentation says that you can add a parameter of type ITestOutputHelper
to the constructor of the test class. I don't see anything that says you can add it as a parameter to the constructor of a test fixture class...
It wouldn't make sense for this output to go via ITestOutputHelper
because the whole point of that mechanism is to allow the output to be associated with a specific test. Your setup/teardown is global, not per-test.
You'll need to find another way to output those diagnostics.
Await Tasks in Test Setup Code in xUnit.net?
xUnit has an IAsyncLifetime
interface for async setup/teardown. The methods you need to implement are Task InitializeAsync()
and Task DisposeAsync()
.
InitializeAsync
is called immediately after the class has been created, before it is used.
DisposeAsync
is called just before IDisposable.Dispose
if the class also implements IDisposable
.
e.g.
public class MyTestFixture : IAsyncLifetime
{
private string someState;
public async Task InitializeAsync()
{
await Task.Run(() => someState = "Hello");
}
public Task DisposeAsync()
{
return Task.CompletedTask;
}
[Fact]
public void TestFoo()
{
Assert.Equal("Hello", someState);
}
}
Run code once before and after ALL tests in xUnit.net
As of Nov 2015 xUnit 2 is out, so there is a canonical way to share features between tests. It is documented here.
Basically you'll need to create a class doing the fixture:
public class DatabaseFixture : IDisposable
{
public DatabaseFixture()
{
Db = new SqlConnection("MyConnectionString");
// ... initialize data in the test database ...
}
public void Dispose()
{
// ... clean up test data from the database ...
}
public SqlConnection Db { get; private set; }
}
A dummy class bearing the CollectionDefinition
attribute.
This class allows Xunit to create a test collection, and will use the given fixture for all test classes of the collection.
[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
// This class has no code, and is never created. Its purpose is simply
// to be the place to apply [CollectionDefinition] and all the
// ICollectionFixture<> interfaces.
}
Then you need to add the collection name over all your test classes.
The test classes can receive the fixture through the constructor.
[Collection("Database collection")]
public class DatabaseTestClass1
{
DatabaseFixture fixture;
public DatabaseTestClass1(DatabaseFixture fixture)
{
this.fixture = fixture;
}
}
It's a bit more verbose than MsTests AssemblyInitialize
since you have to declare on each test class which test collection it belongs, but it's also more modulable (and with MsTests you still need to put a TestClass on your classes)
Note: the samples have been taken from the documentation.
Related Topics
Display Custom Error Page When File Upload Exceeds Allowed Size in ASP.NET MVC
Access Form Component from Another Class
How to Make an Installer for My C# Application
Resharper Conventions for Names of Event Handlers
Entity-Framework Code Is Slow When Using Include() Many Times
How to Split a String into Multiple Values
Quickest Way to Enumerate the Alphabet
Convert Transparent Png to Jpg with Non-Black Background Color
What to Use: Var or Object Name Type
Customattribute Reflects HTML Attribute MVC5
Adding or Subtracting Color from an Image in a Picturebox Using C#
Log4Net, How to Add a Custom Field to My Logging
Spinwait VS Sleep Waiting. Which One to Use
How to Get Byte Array Properly from an Web API Method in C#
Linq to Entities Does Not Recognize the Method 'System.Web.Mvc.Fileresult'