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.