AutoFixture + NSubstitute +虚拟方法

时间:2018-02-01 23:45:33

标签: unit-testing autofixture nsubstitute

想知道是否有办法使用AutoFixture和NSubstitute在具体类上模拟虚拟方法。我已经能够轻松地使用Moq,这可以在这里看到:

public class SomeConcreteClass
{
    public string MethodA()
    {
        return MethodB();
    }

    public virtual string MethodB()
    {
        return "AAA";
    }
}

[TestFixture]
public class SomeConcreteClassTests
{
    private IFixture _fixture;
    private SomeConcreteClass _someConcreteClass;

    [SetUp]
    protected void Setup()
    {
        _fixture = new Fixture()
            .Customize(new AutoMoqCustomization());
        var someConcreteClassMock = _fixture.Create<Mock<SomeConcreteClass>>();
        _someConcreteClass = someConcreteClassMock.Object;
        someConcreteClassMock.CallBase = true;
    }

    [Test]
    public void SomeScenario()
    {
        Mock.Get(_someConcreteClass).Setup(m => m.MethodB()).Returns("BBB");
        var actual = _someConcreteClass.MethodA();
        actual.ShouldBe("BBB");
    }
}

1 个答案:

答案 0 :(得分:2)

如果您使用AutoFixture对Parametrised Tests的支持,最好能够实现这一点,此处使用xUnit.net进行说明(但是,IIRC,对NUnit有类似的支持):

[Theory, AutoNSubstituteData]
public void ImplicitSubtituteViaAttribute([Substitute]SomeConcreteClass scc)
{
    scc.MethodB().Returns("BBB");
    var actual = scc.MethodB();
    Assert.Equal("BBB", actual);
}

使用[Substitute]属性可以明确告诉AutoFixture,虽然你要求一个具体的类,它应该通过NSubstitute创建它,以便你可以覆盖它可能拥有的任何虚拟成员。

AutoNSubstituteData的定义如下:

public class AutoNSubstituteDataAttribute : AutoDataAttribute
{
    public AutoNSubstituteDataAttribute() :
        base(() => new Fixture().Customize(new AutoNSubstituteCustomization()))
    {
    }
}

AutoDataAttribute来自AutoFixture.Xunit2,但如果您更喜欢NUnit而不是xUnit.net,那么您应该能够使用AutoFixture.NUnit3

否则,我不确定您是否可以获得与AutoFixture.AutoMoq完全相同的结果。在这个退化的例子中,你可以这样做:

[Fact]
public void ImperativeWorkaround()
{
    var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
    fixture.Register(() => Substitute.For<SomeConcreteClass>());
    var scc = fixture.Create<SomeConcreteClass>();
    scc.MethodB().Returns("BBB");

    var actual = scc.MethodB();

    Assert.Equal("BBB", actual);
}

然而,这是毫无意义的,因为你可以写下这个:

[Fact]
public void Reduction()
{
    var scc = Substitute.For<SomeConcreteClass>();
    scc.MethodB().Returns("BBB");

    var actual = scc.MethodB();

    Assert.Equal("BBB", actual);
}

换句话说,AutoFixture在该变通办法中实际上并没有任何事情。

我可以想象真正的问题是,在实际使用中,所讨论的具体类具有您希望用数据填充的其他成员或构造函数数据。问题在于,由于NSubstitute的设计方式,我不知道你有什么方法可以声明性地要求替换&#39 ;;你必须使用Substitute.For方法,然后完全缩短AutoFixture挂钩进程并添加自己行为的能力。

使用Moq,这是可能的,因为在OP中,您不会向SomeConcreteClass对象询问AutoFixture,而是要求Mock<SomeConcreteClass>,并且可以使AutoFixture区分。

换句话说,Moq遵循Zen of Python 显式优于隐式,这使得它可扩展到不容易用NSubstitute实现的程度。出于这个原因,我一直认为Moq拥有更好的API。