使用 NSubstitute、AutoFixture 和 AutoFixture.AutoNSubstitute 替换方法 return

Substituting a method return using NSubstitute, AutoFixture and AutoFixture.AutoNSubstitute

我正在尝试使用 NSubstitute (1.8.2)、AutoFixture (3.33) 和 AutoFixture.AutoNSubstitute (3.33),如下所示:

我有一个 poco,它有一个方法并在我的应用程序中使用。为了测试我的应用程序,我需要从方法中模拟 poco 及其 returns。

这是 poco(根据我们的实际模型简化而来)

public class SamplePoco
{
    public string SampleString { get; set; }

    public virtual string GetFormattedString()
    {
        return this.SampleString + " formatted";
    }
}

和这个测试

[TestMethod]
public void SampleTest()
{
    var fixture = new Fixture().Customize(new AutoConfiguredNSubstituteCustomization());

    var substitute = fixture.Create<SamplePoco>();

    var formattedString = fixture.Create<string>();

    substitute.GetFormattedString().Returns(formattedString);

    // ... test goes here
}

我已经使用为 AutoFixture.AutoMoq 找到的代码示例确定了这一点,因为我无法为 AutoFixture.AutoNSubstitute.

找到任何特定示例

但是,此操作失败并出现以下错误:

NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException: Could not find a call to return from.

我做错了什么?

使用 NSubstitute 按预期工作:

[TestMethod]
public void SampleTest()
{
    var fixture = new Fixture().Customize(new AutoConfiguredNSubstituteCustomization());

    var substitute = Substitute.For<SamplePoco>();

    var formattedString = fixture.Create<string>();

    substitute.GetFormattedString().Returns(formattedString);

    // ... test goes here
}

但是,我想使用AutoFixture,因为实际的poco有更多的属性和方法,方法比这个简单的例子更复杂。

如您所写,SamplePoco class 是 POCO,因此当您在第一次测试中调用 fixture.Create<SamplePoco>() 时,您将获得 [= 的全新实例12=] class 由 AutoFixture 使用反射和调用默认构造函数创建。

我认为你的第一个测试很好,AutoFixture 还创建了一个 SampleString 所以,你不需要存根 GetFormattedString 方法。

从测试的角度来看,您的 GetFormattedString 方法包含行为,因此您应该以这种方式测试它:

public void SampleTest()
{
    var fixture = new Fixture().Customize(new AutoConfiguredNSubstituteCustomization());

   var poco = fixture.Create<SamplePoco>();
   Assert.AreEquals(string.Format("{0} {1}", poco.SampleString, "formatted"), poco.GetFormattedString());
}
如果要求 AutoFixture 创建抽象实例(接口或抽象 class),则使用

AutoConfiguredNSubstituteCustomization 并且还将该抽象的其他成员设置为 return 来自 AutoFixture

的值

但是如果你想明确地告诉 AutoFixture 使用 NSubstitute 创建 POCO class 你可以结合使用 AutoDataAttributeSubstituteAttribute。有关此的更多信息,您可以找到 here


编辑

如果您使用的测试框架不允许使用 AutoData 功能,您可以创建自定义来更改 SamplePoco class 的 AutoFixture 行为。

public class SamplePocoSubstituteCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Register(() => Substitute.For<SamplePoco>());
    }
}

[TestMethod]
public void SampleTest()
{
    var fixture = new Fixture().Customize(new AutoConfiguredNSubstituteCustomization())
                                   .Customize(new SamplePocoSubstituteCustomization());

    var substitute = fixture.Create<SamplePoco>();

    var formattedString = fixture.Create<string>();

    substitute.GetFormattedString().Returns(formattedString);

    // ... test goes here
}