sinsedrix
sinsedrix

Reputation: 4775

xUnit generic theories generated by introspection

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

Answers (1)

voidengine
voidengine

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: report

Upvotes: 2

Related Questions