Nsubstitute: Calling .Returns with the return value of a previously-configured substitute results in default value instead

Created on 24 Dec 2019  路  4Comments  路  Source: nsubstitute/NSubstitute

I'm not sure how to describe the situation better than the title, but here is the test (using NUnit and Shouldly)

test2.Id.ShouldBe(test1.Id); fails because test2.Id returns null.

public class Tests
{
  [Test]
  public void Test()
  {
    var test1 = Substitute.For<TestThing>();
    test1.Id.Returns(45);

    var test2 = Substitute.For<TestThing>();
    test2.Id.Returns(test1.Id);

    test2.Id.ShouldBe(test1.Id);
  }

  public interface TestThing
  {
    int? Id { get; }
  }
}

This, however, works:

[Test]
public void Test()
{
  var test1 = Substitute.For<TestThing>();
  test1.Id.Returns(45);

  var test1Id = test1.Id;
  var test2 = Substitute.For<TestThing>();
  test2.Id.Returns(test1Id);

  test2.Id.ShouldBe(test1.Id);
}

public interface TestThing
{
 int? Id { get; }
}

It seems like this must be a simple mistake I'm making, but I can't find it. What am I doing wrong here?

All 4 comments

Hi @joelhoward0 ,

Thanks for the great code example. This isn't really your mistake; it is an unfortunate downside to NSubstitute's syntax. The problem is that calling test1 while stubbing test2 confuses NSubstitute as to which call is being stubbed. For a detailed explanation of a similar case, see this StackOverflow answer.

To work around this, replace the stub with test2.Id.Returns(x => test1.Id);, which makes the test pass on my machine (i.e. use (x => test1.Id) lambda instead of just (test1.Id)). This will defer calling test1.Id while stubbing the property, so NSubstitute knows your just dealing with the test2 call.

Hope this helps.

I see. Thank you for the explanation and for the workaround! It's better than what I had been doing.

@dtchepak is this something which should be picked up by NS4000?
Original issue https://github.com/nsubstitute/NSubstitute.Analyzers/issues/12 was not describing this particular corner-case but maybe we should extend NS4000 or introduce new warning?

@tpodolak I think it would be good if it is possible to add to NS4000. 馃憤

Was this page helpful?
0 / 5 - 0 ratings