Reputation: 4775
I'd like to generate theories dynamically for some classes that implement a given interface.
At this time, I use introspection to get types of implementing classes:
IEnumerable<Type> srvTypes = typeof(BaseService<>).Assembly.GetTypes()
.Where(p => typeof(IBaseService).IsAssignableFrom(p) && !p.IsAbstract);
IEnumerable<IBaseService> srvs = srvTypes.Select(st => Activator.CreateInstance(st));
Then I can run each method of the service, if it doesn't raise an exception, I consider the test as OK:
Assert.All(srvs, srv => srv.GetX());
Assert.All(srvs, srv => srv.DoY());
Assert.All(srvs, srv => srv.SyncZ());
For these lines, I'll only get 3 test results, but I'd like to have one per service.
Is there a way to tell xUnit to run a test for each implementing class?
NB: I don't want to write each class name in a theory attribute, It should be dynamic.
Upvotes: 0
Views: 1126
Reputation: 2579
You can use your reflection code as a source of data for the theory:
public interface ICanDoX
{
bool DoX();
}
public class A : ICanDoX
{
public bool DoX() => true;
}
public class B : ICanDoX
{
public bool DoX() => false;
}
public class ImplementorTests
{
public static TheoryData<ICanDoX> Implementors;
static ImplementorTests()
{
var instances = typeof(ICanDoX).Assembly.GetTypes()
.Where(t => typeof(ICanDoX).IsAssignableFrom(t) && !t.IsAbstract)
.Select(t => (ICanDoX)Activator.CreateInstance(t));
Implementors = new TheoryData<ICanDoX>();
foreach (var instance in instances)
Implementors.Add(instance);
}
[Theory]
[MemberData(nameof(Implementors))]
public void DoX_Succeeds(ICanDoX icandox)
{
Assert.True(icandox.DoX());
}
}
In test results, you will have a record for each of the implementing class like this:
Upvotes: 2