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.