3

関数を呼び出すようにモックをセットアップするときに、NSubstitute から予期していなかった動作が発生します。動作の単純化されたバージョンは次のとおりです。

[Test]
public void NSubstituteTest()
{
    var mockedFoo = Substitute.For<IFoo>();

    mockedFoo.GenerateString(Arg.Any<string>()).Returns(x => GetValue(x.Args()[0]));
    mockedFoo.GenerateString("0").Returns("hi");


    string result1 = mockedFoo.GenerateString("0");
    string result2 = mockedFoo.GenerateString("1");

    Assert.AreEqual("hi", result1);
    Assert.AreEqual("1", result2);
}

private string GetValue(object val)
{
    string returnValue = val != null ? val.ToString() : "I am null";
    System.Diagnostics.Trace.WriteLine(returnValue);
    return returnValue;
}

テストはパスしますが、次の出力が得られます: 0 1

これは、mockedFoo.GenerateString("0"); への呼び出しを示しています。実際には GetValue() 関数が呼び出されます。

Moqで同じことをすると:

[Test]
public void MoqTest()
{
    var mockedFoo = new Mock<IFoo>();

    mockedFoo.Setup(x => x.GenerateString(It.IsAny<string>())).Returns((object s) => GetValue(s));
    mockedFoo.Setup(x => x.GenerateString("0")).Returns("hi");


    string result1 = mockedFoo.Object.GenerateString("0");
    string result2 = mockedFoo.Object.GenerateString("1");

    Assert.AreEqual("hi", result1);
    Assert.AreEqual("1", result2);
}

その後、私のテストも合格しますが、結果は得られます: 1

関数が呼び出されなかったことを示します。

この動作はどこかで説明されていますか、それとも間違った方法で何かを設定していますか?

4

1 に答える 1

5

This is a side-effect of how NSubstitute works: to get that particular syntax it needs to actually call the method to get a reference to that method.

Moq and others use lambdas and can pick the particular method out from there, without the need to run the method itself. (This means NSubstitute also fails to detect or throw on non-virtual method calls.)

The next release will have a work-around for some cases where this is causing problems (albeit a non-ideal one: you'll need to have an argument matcher in the call that sets the return so NSub knows in advance it is not a real call), but the fundamental issue of having to intercept actual method calls will remain.

于 2011-08-02T08:05:46.140 に答える