Search code examples
c#xunitautofixtureautomoq

Test class simplification without generics


I have a large collection of models that all implement IEquatable<T> for which I have several similar looking test classes, aside from the SUTs type. The tests validate the implementation and a few other common aspects all implemented by the models under test.

Using an abstract generic test class does not accomplish much, I loose the compile time overload resolution on the operators and I have to implement a derived test class for each type anyway.

Using the MemberData attribute helps eliminate the need for derived test classes, however the compile time overload resolution on the operators remains.

Does another approach exist such as InlineData where I maintain the compile time overload resolution on the operators and have a single collection of objects (whether they are types or not) to invoke the test methods?

In the example below, I use MemberData but must use reflection to invoke the == and != operators and the test method signatures are less than optimal as they are unused (only the generic type parameter is used).

[Theory]
[MemberData(nameof(GetModelTypes))]
public void MyTest<T>(T _)
    where T : class, new()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    // Add any known type customization's...

    T t = fixture.Create<T>();
    // Implement remaining generic test body.
}

public static IEnumerable<object[]> GetModelTypes() =>
{
    new object[] {new ModelA()},
    new object[] {new ModelB()},
    /* ... */
}

Does anyone know a methodology that will allow me to maintain one collection of objects and test with compile time overload resolution?


Solution

  • You can write generic unit test classes with xUnit.net like this:

    public abstract class ModelTests<T>
    {
        [Fact]
        public void MyTest()
        {
            var fixture = new Fixture();
            var sut = fixture.Create<T>();
    
            // The rest of the test goes here...
        }
    
        // More tests go here...
    }
    
    public class ModelATests : ModelTests<ModelA> { }
    public class ModelBTests : ModelTests<ModelB> { }
    

    That said, if you have a multitude of similar-looking tests, it may be worthwhile looking into AutoFixture.Idioms, and particularly its IdiomaticAssertion base class.