Typesafety in xUnit with TheoryData<T>

3/5/2024
1 minute read

I recently discovered this small but very useful utility in xUnit: TheoryData<T>.

The problem

I had the following code in my repository:

public static IEnumerable<object[]> Data => new List<object[]>
    {
        new object[] { new Action<IServiceCollection>(services => services.UseSqliteAsStorageProvider()) },
        new object[] { new Action<IServiceCollection>(services => services.UseSqlAsStorageProvider()) },
        new object[] { new Action<IServiceCollection>(services => services.UseInMemoryAsStorageProvider()) },
        new object[] { new Action<IServiceCollection>(services => services.UseRavenDbAsStorageProvider()) },
        new object[] { new Action<IServiceCollection>(services => services.UseMySqlAsStorageProvider()) },
    };

[Theory]
[MemberData(nameof(Data))]
public void GivenAlreadyRegisteredRepository_WhenTryingToAddAnotherStorage_ThenException(Action<IServiceCollection> act)

The issue her eis that Data is of type IEnumerable<object[]> and the act parameter is of type Action<IServiceCollection>. This means that I can pass anything to the method and the compiler will happily accept it. Here is where the TheoryData<T> comes in.

The solution

TheoryData<T> is a class that allows to wrap the data in a strongly typed way. Here is how I used it:

public static TheoryData<Action<IServiceCollection>> Data => new() 
{
    services => services.UseSqliteAsStorageProvider(),
    services => services.UseSqlAsStorageProvider(),
    services => services.UseInMemoryAsStorageProvider(),
    services => services.UseRavenDbAsStorageProvider(),
    services => services.UseMySqlAsStorageProvider()
};

[Theory]
[MemberData(nameof(Data))]
public void GivenAlreadyRegisteredRepository_WhenTryingToAddAnotherStorage_ThenException(Action<IServiceCollection> act)

Exactly the same test, but way more typesafe. Now the compiler will not allow me to pass anything other than Action<IServiceCollection> to the method.

xUnit v3 and some stuff about TUnit

I know that there is a lot of fuse about TUnit and I am here writing about xUnit. I might cover TUnit in the future, but for now, the topic is the v3 prerelease of xUnit!

Why I like and prefer xUnit

In almost all of my projects, I only use xUnit, and here is a small love letter. Especially the one fact I do think makes it a good choice!

5 useful extensions for Task<T> in .NET

In this short blog post, I will show you 5 useful extensions for Task in .NET. We will build them as extension methods, so there are easy to use. On top, I will show a small example of how to use them. So let's go!

An error has occurred. This application may no longer respond until reloaded. Reload x