0

I have the following test code using NSubstitute:

[TestMethod]
public void Test()
{
    var foo = Substitute.For<IFoo>();
    foo.Foo(Arg.Is<Bar>(b => !b.X)).Returns(0); // Line 1
    foo.Foo(Arg.Is<Bar>(b => b.X)).Returns(1); // Line 2
}

public interface IFoo
{
    int Foo(Bar b);
}

public class Bar
{
    public bool X;
}

When line 2 is executed, an exception is thrown:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

However, the exception is not thrown if I change !b.X to b != null && !b.X. It seems that the lambda expression in line 1 is being evaluated with a null lambda variable when line 2 is called.

My intention is to have more than one call configuration for the method I'm mocking. So, am I doing this wrong? Is there another way to do this?

Neo
  • 4,145
  • 6
  • 53
  • 76
  • Is the code exactly the same in both projects? If the `foo` reference is shared between tests maybe it is a previously run test causing an issue. In that case, try adding the [NSubstitute.Analyzers](http://nsubstitute.github.io/help/nsubstitute-analysers/) package and see if it detects any potential issues. – David Tchepak Dec 19 '18 at 02:40
  • @DavidTchepak, yes, the code is identical in both projects, and `foo` is a local variable, so it can't be shared between tests. – Neo Dec 19 '18 at 10:21
  • @DavidTchepak, OK, I was being stupid. I installed dotPeek and debugged into NSubstitute.dll and it turned out an exception was indeed being thrown in my other project, but breaking on `NullReferenceException` was disabled! Oops! In the project where I was seeing it, it was because I had Just My Code disabled. But it does highlight an important problem (the _actual_ problem I'm having), and so I've revised the question accordingly. – Neo Dec 19 '18 at 12:59
  • @Neo The desired behavior can be achieved with `foo.Foo(Arg.Any()).Returns(args => args.Arg().X ? 1 : 0);` – Nkosi Dec 19 '18 at 13:39
  • Which version of NSubstitute are you using? The following passes for me with NSubstitute 3.1.0: https://gist.github.com/dtchepak/87e6bf6a17e448b97ce2f0c35c8e9ae3 – David Tchepak Dec 19 '18 at 21:43

1 Answers1

1

The problem is that the last setup on a mocked member overrides any previous arrangements.

The desired behavior can be achieved with

//Arrange
var foo = Substitute.For<IFoo>();
foo.Foo(Arg.Any<Bar>()).Returns(args => args.Arg<Bar>().X ? 1 : 0); 

//...
Nkosi
  • 235,767
  • 35
  • 427
  • 472