DEV Community

tswiftma
tswiftma

Posted on

Initialize asynchronous data in XUnit Collections for sharing data between tests

By its design XUnit doesn't like to share data between tests like NUnit. XUnit has created Collection Fixtures as a method to share data between your tests and test classes. While this approach generally works I found that almost all the test data I needed to share between tests was created asynchronously! We live in an Asynchronous world now.

If you reference the XUnit link above you'll see that they initialize their example DatabaseFixture class like so:

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; }
}
Enter fullscreen mode Exit fullscreen mode

The problem with the above code is that I can't create test data with an async/await call. There is a fairly easy way around this problem that XUnit should really document. You can derive your DatabaseFixture class from IAsyncLifeTime to provide asynchronous lifetime functionality for your test data that can be referenced in every test. To do this you create and destroy all of your test data in the InitializeAsync() and DisposeAsync() methods like so:

public class DatabaseFixture : IAsyncLifeTime
{
    // ... create your shared vars here

    public async Task InitializeAsync()
    {
        // ... initialize data in the test database and/or use async calls here ...
    }

    public async Task DisposeAsync()
    {
        // ... clean up test data from the database with and use async calls here...
    }    
}
Enter fullscreen mode Exit fullscreen mode

Now the above code example only replaces the initial class creation from XUnit. You still need to create an XUnit CollectionDefinition and Collection with all of your tests as per the examples on the XUnit page.

Note that using the IAsyncLifetime derived test class is an excellent opportunity to create your own classes to store test data. Try creating a a new class file MyTestData to store whatever you need. Could be strings, lists, guids, etc. Then under the class section // ... create your shared vars here initialize your class object:

public List<MyTestData> _testData { get; set; }
Enter fullscreen mode Exit fullscreen mode

You now can use _testData to store any type of test data you create and share it with all your tests. Pretty darn awesome.

Top comments (1)

Collapse
 
xaberue profile image
Xavier Abelaira Rueda

Nice article, great tip! you saved my day! I was struggling with this, Xunit clearly has a not to structured and clear documentation in some scenarios.

With this particular scenario, I have come to think about going to NUnit since it more clearly covered the purpose I was looking for...

BTW small typo in the DatabaseFixture code snippet, the interface is IAsyncLifetime (with the lowercase T)

Thank you so much