AutoFixture AutoDataAttribute 单元测试中的 ArgumentNullException

ArgumentNullException in a unit test for AutoFixture AutoDataAttribute

我正在为 related SO question 编写 ApiControllerConventions 的单元测试,我编写了 AutoMoqApiControllerDataAttribute 以将此 ICustomization 集成到 xUnit.net 中。

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

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

我试过像这样为此属性编写单元测试:

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);
}

失败,异常来自 AutoDataAttribute:

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

我认为这与我对 AutoMoqDataAttribute 的使用有关,所以我恢复到原版 Fact,同样的异常仍然存在:

[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);
}

为什么我得到异常?我显然嘲笑了 IFixture 并且它绝对不是空的。

当您遇到异常时,查看调用堆栈总是一个好主意。异常不是在 AutoMoqApiControllerDataAttribute 中抛出,而是在 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()

虽然 fixture 在传递给 AutoMoqApiControllerDataAttribute 时不是 null,但在传递给 null =19=].

为什么?

考虑对 base 的调用:

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

哪个值正在传递给 base

不是 fixture,而是调用 fixture.Customize.

return 值

测试没有为此方法调用设置 return 值,因此 Moq 默认为该类型的默认值。由于 IFixture 是引用类型,这意味着 null,然后 null 值将传递给 base.

您可以通过在测试中使用 return 值配置 mockFixture 轻松解决问题:

[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());
}

现在我的测试通过了。

这不是 AutoFixture 特有的问题。您可以使用任何 Fluent Interface.

重现它