使用AutoMoq属性

时间:2016-04-28 15:18:18

标签: c# unit-testing autofixture

我想知道在使用设置AutoData的测试用例时,是否有一种方法可以在调用受测系统(SUT)的构造函数之前为依赖项设置模拟。< / p>

我的SUT看起来像:

class Sut
{
    private readonly IFoo foo;
    public Sut(IFooFactory factory)
    {
        this.foo = factory.Build(1, 2);
    }

    public IFoo Foo
    {
        get
        {
            return this.foo;
        }
    }
}

所以我写的测试看起来像是:

[Theory]
[AutoData]
internal void Foo_IsCorrectlySet_Test(
    [Frozen] Mock<IFooFactory> fooFactory,
    IFoo foo,
    Sut sut)
{
    fooFactory.Setup(mock => mock.Build(1, 2))
        .Returns(foo)
        .Verifiable();

    var actual = sut.Foo;

    Assert.Equal(foo, sut);
    fooFactory.Verify();
}

显然,此测试失败,因为Sut的构造函数在我能够设置IFooFactory之前运行。所以我认为我可以在测试中将Sut的声明更改为Lazy<Sut>。 但是,在运行实际测试代码之前,构造函数仍然运行,这意味着我的测试将失败。

现在我知道我可以使用实际的Fixture对象轻松设置此测试并手动创建我的所有对象并在我打电话创建Sut之前设置它,这很好,但是我&# 39;我想让我的测试大致保持一致,因此我想知道是否有一种方法可以使用AutoData属性设置我的测试但是在所有设置完成之后才运行构造函数?

2 个答案:

答案 0 :(得分:5)

AutoFixture最初是作为测试驱动开发(TDD)的工具而构建的,TDD完全是关于反馈的。本着GOOS的精神,你应该倾听你的测试。如果测试难以编写,则应考虑API设计。 AutoFixture倾向于放大那种反馈,这也可能就是这种情况。

考虑Sut类的不变量。由于它具有只读IFoo类字段,因此我将其解释为IFoo是该类的依赖项的强烈指示。

如果是这种情况,则通过构造函数而不是IFoo注入IFooFactory

public class Sut
{
    private readonly IFoo foo;
    public Sut(IFoo foo)
    {
        this.foo = foo;
    }

    public IFoo Foo
    {
        get { return this.foo; }
    }
}

您仍然可以使用应用程序Composition Root中的IFooFactory 撰写

var sut = new Sut(aFactory.Build(1, 2));

这将使测试更容易编写。我甚至无法向您展示上述测试在重构中的表现,因为它是多余的,可以(并且应该)删除。

FWIW,上面提出的原始设计违反了Nikola Malovic的IoC第4定律constructors should do no work

答案 1 :(得分:1)

您可以使用Fixture object pattern。 这允许您在创建sut之前设置模拟。

以下内容:

    private class Fixture
    {
        public Mock<FooFactory> FooFactoryMock { get; set; } = new Mock<FooFactory>();
        public Sut GetSut()
        {
            return new Sut(FooFactoryMock.Object);
        }
    }

    [Theory]
    [AutoData]
    internal void Foo_IsCorrectlySet_Test(
        IFoo foo)
    {
        var fixture = new Fixture();
        fixture.FooFactory.Setup(mock => mock.Build(1, 2))
            .Returns(foo)
            .Verifiable();

        var sut = fixture.GetSut();
        var actual = sut.Foo;

        Assert.Equal(foo, sut);
        fooFactory.Verify();
    }