rexcfnghk
rexcfnghk

Reputation: 15432

ArgumentNullException in a unit test for AutoFixture AutoDataAttribute

I was writing a unit test for ApiControllerConventions from a related SO question and I wrote a AutoMoqApiControllerDataAttribute to integrate this ICustomization in xUnit.net.

public class AutoMoqApiControllerDataAttribute : AutoDataAttribute
{
    public AutoMoqApiControllerDataAttribute() : this(new Fixture())
    {
    }

    public AutoMoqApiControllerDataAttribute(IFixture fixture) : base(
        fixture.Customize(new ApiControllerConventions()))
    {
    }
}

I tried writing a unit test for this attribute like this:

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute() : this(new Fixture())
    {
    }

    public AutoMoqDataAttribute(IFixture fixture) : 
        base(fixture.Customize(new AutoMoqCustomization()))
    {
    }
}

[Theory, AutoMoqData]
public void AutoMoqApiControllerDataAttribute_ContainsCorrectCustomization(
    Mock<IFixture> mockFixture)
{
    // Arrange
    mockFixture.Setup(f => f.Customize(It.IsAny<ApiControllerConventions>())).Verifiable();

    // Act
    var sut = new AutoMoqApiControllerDataAttribute(mockFixture.Object);

    // Assert
    mockFixture.Verify(f => f.Customize(It.IsAny<ApiControllerConventions>()), Times.Once);
}

This fails with an exception from AutoDataAttribute:

System.ArgumentNullException Value cannot be null. Parameter name: fixture at Ploeh.AutoFixture.Xunit2.AutoDataAttribute..ctor(IFixture fixture)

I thought this is related to my usage of the AutoMoqDataAttribute so I reverted to a vanilla Fact, same exception still:

[Fact]
public void AutoMoqApiControllerDataAttribute_ContainsCorrectCustomization()
{
    // Arrange
    var mockFixture = new Mock<IFixture>();
    mockFixture.Setup(f => f.Customize(It.IsAny<ApiControllerConventions>())).Verifiable();

    // Act
    var sut = new AutoMoqApiControllerDataAttribute(mockFixture.Object);

    // Assert
    mockFixture.Verify(f => f.Customize(It.IsAny<ApiControllerConventions>()), Times.Once);
}

Why am I getting the exception? I obviously have the IFixture mocked and it is definitely not null.

Upvotes: 1

Views: 1972

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233125

When you get an exception, it's always a good idea to look at the call stack. The exception isn't thrown in AutoMoqApiControllerDataAttribute, but in AutoDataAttribute:

System.ArgumentNullException : Value cannot be null.
Parameter name: fixture
    at Ploeh.AutoFixture.Xunit2.AutoDataAttribute..ctor(IFixture fixture)
    AutoMoqApiControllerDataAttribute.cs(12,0): at _44380395.AutoMoqApiControllerDataAttribute..ctor(IFixture fixture)
    Tests.cs(22,0): at _44380395.Tests.AutoMoqApiControllerDataAttribute_ContainsCorrectCustomization()

While fixture isn't null when it's passed to AutoMoqApiControllerDataAttribute, it is null when passed to base(IFixture).

Why?

Consider the call to base:

base(fixture.Customize(new ApiControllerConventions()))

Which value is being passed to base?

Not fixture, but the return value from invoking fixture.Customize.

The test doesn't set up a return value for this method call, so Moq defaults to the default value for the type. Since IFixture is a reference type, that means null, and that null value is then passed to base.

You can easily address the problem by configuring mockFixture with a return value in the test:

[Fact]
public void AutoMoqApiControllerDataAttribute_ContainsCorrectCustomization()
{
    // Arrange
    var mockFixture = new Mock<IFixture>();
    mockFixture
        .Setup(f => f.Customize(It.IsAny<ApiControllerConventions>()))
        .Returns(mockFixture.Object)
        .Verifiable();

    // Act
    var sut = new AutoMoqApiControllerDataAttribute(mockFixture.Object);

    // Assert
    mockFixture.Verify(
        f => f.Customize(It.IsAny<ApiControllerConventions>()),
        Times.Once());
}

Now the test passes in my repro.

This isn't a problem specific to AutoFixture. You could reproduce it with any Fluent Interface.

Upvotes: 2

Related Questions