Unit Testing Interfaces with xUnit Theories

Wednesday, June 10, 2009 – 8:46 PM

Someone at p&p just asked me this and I thought it was worth blogging about.

Suppose I have an interface IIntegrate that I’ve implemented for a number of concrete types within my application. In principle I can use an xUnit Theory to test the behavior of each interface. Something like this:

    [Theory]
    [InlineConstructorData(typeof(LeapfrogNativeIntegrator))]
    [InlineConstructorData(typeof(LeapfrogNativeParallelIntegrator))]
    [InlineConstructorData(typeof(ForwardEulerNativeVectorIntegrator))]
    public void IntegrateThrowsIfNotInitialized(IIntegrate target)
    {
        Body[] bodies = new BinaryUniverseInitializer().Initialize();

        Assert.Throws<InvalidOperationException>(
            () => target.Integrate(0.01, bodies));
    }

Here I have a Theory which tests all three integrator implementations to make sure they obey the interface contract, namely the Integrate method cannot be called before the Initialize method.

Before you dash off to try this there’s the InlineConstructorDataAttribute to consider. I actually wrote this to get around some of the limitations with the xUnit InlineData attribute and attributes in general. Attributes cannot take arbitrary (user defined) types as parameters, only system types. The InlineConstructorDataAttribute takes a Type parameter and creates an instance of it:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    [CLSCompliant(false)]
    public sealed class InlineConstructorDataAttribute : DataAttribute
    {
        private readonly Type _type;

        public InlineConstructorDataAttribute(Type constructedType)
        {
            _type = constructedType;
        }

        public Type ConstructedType
        {
            get { return _type; }
        }

        public override IEnumerable<object[]> GetData(MethodInfo methodUnderTest,
             Type[] parameterTypes)
        {
            if (parameterTypes.Length != 1)
                yield break;

            ConstructorInfo info = _type.GetConstructor(
                BindingFlags.Public | BindingFlags.Instance,
                 null, new Type[] {}, null);
            if (info == null)
                yield break;
            yield return new object[] {info.Invoke(new object[] {})};
        }
    }

The only limitation of this approach is it assumes that your constructedType has a parameterless constructor.

If this isn’t the case then you have two options. You could either extend the code above to allow the attribute to take further parameters which would be used to construct the required type. Alternatively you could use the xUnit PropertyData attribute. Here’s a test that uses this alternative. In my opinion this is less expressive than

    public static IEnumerable<object[]> ObjectFactory
    {
        get
        {
            yield return new object[] { new ParameterlessCtorClass() };
            yield return new object[] { new ParameterizedCtorClass("2") };
        }
    }

    [Theory]
    [PropertyData("ObjectFactory")]
    public void UsePropertyDataToCreateObjects(IBase typeUnderTest)
    {
        Assert.True(typeof(IBase).IsAssignableFrom(typeUnderTest.GetType()));
    }

It’s definitely possible to over use this technique. Typically I start off using TDD on a single interface implementation and refactor to theories as I see fit later. The whole point is to make the tests more expressive so theory code which ends up harder to read than a series of individual tests (xUnit Facts) is not to goal.

Incidentally the alternative I’ve used with other frameworks which don’t support anything like xUnit Theories is to push the tests into an abstract base class which implements an abstract Create method

    public class LeapfrogNativeIntegratorTests : IIntegrateBaseTests
    {
        protected override IIntegrate Create()
        {
            return new LeapfrogNativeIntegrator();
        }
    }

    public class LeapfrogNativeParallelIntegratorTests : IIntegrateBaseTests
    {
        protected override IIntegrate Create()
        {
            return new LeapfrogNativeParallelIntegrator();
        }
    }

    public abstract class IIntegrateBaseTests
    {
        protected abstract IIntegrate Create();

        [Fact]
        public void IntegrateThrowsIfNotInitialized()
        {
            IIntegrate target = Create();
            Body[] bodies = new BinaryUniverseInitializer().Initialize();

            Assert.Throws<InvalidOperationException>(
                () => target.Integrate(0.01, bodies));
        }
    }

I wouldn’t do this with xUnit but it’s an alternative if you’re using something like MSTest. In my opinion this is a lot less clear.

  1. 2 Responses to “Unit Testing Interfaces with xUnit Theories”

  2. I created something similar a while back that uses reflection to find appropriate instances for each method argument. For your example, you could specify a single [InstanceData] instead of multiple [InlineConstructorData(…)] attributes (though I admit your method is clearer :). Also supports non-default constructors generic methods.

    http://typeresolver.codeplex.com/

    By Emperor XLII on Jun 11, 2009

  1. 1 Trackback(s)

  2. Jun 11, 2009: Twitted by bentayloruk

Sorry, comments for this entry are closed at this time.