3

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?

Jon
  • 561
  • 4
  • 14
  • Following on from my answer, if you are still happy to use NSubstitute and would like to discuss other ideas to work around this constraint please post to the [mailing list](http://groups.google.com/group/nsubstitute). (For example, we could look at extending the When..Do syntax to support Returns, which would give the option of deferred execution for cases like these where it is needed.) – David Tchepak Aug 02 '11 at 09:17
  • Sounds great - I still feel the syntax of NSubstitute overweights this "issue" and I will keep using it – Jon Aug 02 '11 at 12:27

1 Answers1

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.

David Tchepak
  • 9,826
  • 2
  • 56
  • 68
  • This is actually quite annoying because I have to ensure that for all classes I am substituting should have valid inputs in my tests otherwise they may break as Nsubstitute will invoke actual methods. Do we have any work around for this problem. – Rahul Garg Jan 07 '17 at 19:34
  • Is there an update on this? Having exactly the same behavior with ``. – Nikita R. Mar 30 '17 at 23:36
  • @NikitaG. No, this behaviour remains as in the original question. There are a few workarounds, like only "activating" the callback logic at a later point in the test, but it's a tad messy. – David Tchepak Mar 30 '17 at 23:46