简体   繁体   中英

Function is called when I do not expect it to with NSubstitute

I am getting a behaviour I didnt expect from NSubstitute when setting up my mocks to call a function. A simplified version of the behavuiour is

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

The test passes but I get the output: 0 1

This indicates that the call to mockedFoo.GenerateString("0"); actually results in a call to the GetValue() function.

If I do the same with 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);
}

Then my tests also passes but I get the result: 1

Indicating the function was not called.

Is this behaviour described somewhere or do I set something up in a wrong way perhaps?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM