Run Code Once Before and After All Tests in Xunit.Net

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.

How to run setup code only once in an xUnit.net test

Following the guidance in this xUnit discussion topic, it looks like you need to implement a constructor on the Fixture and also implement IDisposable. Here's a complete sample that behaves the way you want:

using System;
using System.Diagnostics;
using Xunit;
using Xunit.Sdk;

namespace xUnitSample
{
public class SomeFixture : IDisposable
{
public SomeFixture()
{
Console.WriteLine("SomeFixture ctor: This should only be run once");
}

public void SomeMethod()
{
Console.WriteLine("SomeFixture::SomeMethod()");
}

public void Dispose()
{
Console.WriteLine("SomeFixture: Disposing SomeFixture");
}
}

public class TestSample : IUseFixture<SomeFixture>, IDisposable
{
public void SetFixture(SomeFixture data)
{
Console.WriteLine("TestSample::SetFixture(): Calling SomeMethod");
data.SomeMethod();
}

public TestSample()
{
Console.WriteLine("This should be run once before every test " + DateTime.Now.Ticks);
}

[Fact]
public void Test1()
{
Console.WriteLine("This is test one.");
}

[Fact]
public void Test2()
{
Console.WriteLine("This is test two.");
}

public void Dispose()
{
Console.WriteLine("Disposing");
}
}
}

When running this from the console runner, you'll see the following output:

D:\xUnit>xunit.console.clr4.exe test.dll /html foo.htm xUnit.net
console test runner (64-bit .NET 4.0.30319.17929) Copyright (C)
2007-11 Microsoft Corporation.

xunit.dll: Version 1.9.1.1600 Test assembly: test.dll

SomeFixture ctor: This should only be run once

Tests complete: 2 of 2

SomeFixture: Disposing SomeFixture

2 total, 0 failed, 0 skipped, took 0.686 seconds

Then, when you crack open the test output file foo.htm, you'll see the other test output.

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.

Is it possible to execute code once before all tests run?

FWIW, you can use the AssemblyInitialize attribute to run code before all unit tests in an assembly executes:

[TestClass]
public class SetupAssemblyInitializer
{
[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
// Initalization code goes here
}
}

If you have more than one unit test assembly, I'm not aware of anything that encompasses more than one assembly.

As far as I'm aware, this is as close as you can get to a Main equivalent.

Note that the AssemblyInitialize-decorated method must be in a TestClass-decorated class which contains at least one TestMethod-decorated method, otherwise it will not be executed!

Is there a way to run a setup method asynchronously before every test in an xunit test class?

Implement xUnit's IAsyncLifetime interface. It defines InitializeAsync and DisposeAsync which will be called immediately after construction and immediately before disposal, respectively.

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.

xunit constructor runs before each test

You can use Xunit Class fixtures. When using a class fixture, xUnit.net will ensure that the fixture instance will be created before any of the tests have run, and once all the tests have finished, it will clean up the fixture object by calling Dispose, if present. For example:

//similar to base class
public class DatabaseFixture : IDisposable
{
public SqlConnection Db { get; private set; }
public DatabaseFixture()
{
Db = new SqlConnection("MyConnectionString");

// initialize data in the test database
}

public void Dispose()
{
// clean up test data from the database
}
}

//Class where you want to use shared class instance
public class MyDatabaseTests : IClassFixture<DatabaseFixture>
{
DatabaseFixture dbFixture;

public MyDatabaseTests(DatabaseFixture fixture)
{
this.dbFixture = fixture;
}

// write tests, using dbFixture.Db to get access to the SQL Server
}

For each test, it will create a new instance of MyDatabaseTests, and pass the shared instance of DatabaseFixture to the constructor.

Xunit Documentation here.

Hope it helps.

Edit 28/10
For multiple fixtures you can create a class which encapsulates the other two fixtures as below and create startup fixture to run before db fixture:

public class SecurityTestsFixture : IDisposable
{
public DatabaseFixture Dbfixture { get; private set; }
public StartupTestFixture Startupfixture { get; private set; }

public SecurityTestsFixture()
{
Startupfixture = new StartupTestFixture();
Dbfixture = new DatabaseFixture(Startupfixture);
}

public void Dispose()
{
// clean up code
Dbfixture.Dispose();
}

public class StartupTestFixture
{
public string SqlConnString { get; private set; }
public StartupTestFixture()
{
SqlConnString = ConfigurationManager.AppSettings["SqlConnectionString"];

// other startup code
}
}

public class DatabaseFixture : IDisposable
{
public SqlConnection Db { get; private set; }
public DatabaseFixture(StartupTestFixture sFixture)
{
Db = new SqlConnection(sFixture.SqlConnString);

// initialize data in the test database
}

public void Dispose()
{
// clean up test data from the database
}
}
}

and test class:

public class Xunittests : IClassFixture<SecurityTestsFixture>
{
SecurityTestsFixture _securityFixture;
public Xunittests(SecurityTestsFixture securityfixture)
{
_securityFixture = securityfixture;
}

[Fact(DisplayName = "Successful response Test1")]
public void SuccessfulResponseTest1()
{
var db = _securityFixture.Dbfixture.Db;
//var users = db.Users.FirstOrDefault(x => x.Name == "...");
Assert.Equal("test", "test");
}
}


Related Topics



Leave a reply



Submit