Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSubstitute virtual getter returning substitution using ForPartsOf throws exception

I am trying to mock one property of an object

There is a similar question: Returning the result of a method that returns another substitute throws an exception in NSubstitute But the accepted answer is not working for me.

void Main()
{
    var obj = Substitute.ForPartsOf<MyObject>();
    //WORKS, But I need a partial mock!:
    //var obj = Substitute.For<MyObject>();

    obj.PropClass.Returns(Substitute.For<PropClass>());

    //It's suggestion, Fails, same error:
    //var returnValue = Substitute.For<PropClass>();
    //obj.PropClass.Returns(returnValue);

    //Fails, same error:
    //Lazy implementation of *similar question*
    //Func<PropClass> hello = () => Substitute.For<PropClass>();
    //obj.PropClass.Returns(x => hello());

    //Fails, same error:
    //I believe what *similar question* suggests
    //obj.PropClass.Returns(x => BuildSub());

    obj.PropClass.Dump("Value");
}

public class MyObject
{
    public MyObject()
    {
        _propClasses = new List<PropClass>();
    }
    private readonly IList<PropClass> _propClasses;
    public virtual IEnumerable<PropClass> PropClasses { get { return _propClasses; } }
    public virtual PropClass PropClass { get { return PropClasses.FirstOrDefault(); } }
}
public class PropClass
{
}

public PropClass BuildSub()
{
    return Substitute.For<PropClass>();
}

These fail with the exception:

CouldNotSetReturnDueToTypeMismatchException:
Can not return value of type PropClassProxy_9 for MyObject.get_PropClasses (expected type IEnumerable`1).

Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),
and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).

If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.
Return values cannot be configured for non-virtual/non-abstract members.

Correct use:
  mySub.SomeMethod().Returns(returnValue);

Potentially problematic use:
  mySub.SomeMethod().Returns(ConfigOtherSub());
Instead try:
  var returnValue = ConfigOtherSub();
  mySub.SomeMethod().Returns(returnValue);
like image 566
Thymine Avatar asked Jan 22 '14 21:01

Thymine


People also ask

How do you throw an exception in NSubstitute?

Normally, for synchronous calls, you can just add a . Throws<TException>() after the method you want to mock throwing an exception (or . ThrowsForAnyArgs<TException>() if you don't care about the input arguments).

How do we set a return value for a method call on a substitute?

To set a return value for a method call on a substitute, call the method as normal, then follow it with a call to NSubstitute's Returns() extension method. var calculator = Substitute. For<ICalculator>(); calculator. Add(1, 2).

What is NSubstitute?

NSubstitute is a friendly substitute for . NET mocking libraries. It has a simple, succinct syntax to help developers write clearer tests. NSubstitute is designed for Arrange-Act-Assert (AAA) testing and with Test Driven Development (TDD) in mind.


1 Answers

Ok, this is a bit of a tricky one. First, the solution is to stop obj.PropClass from calling the base implementation:

obj.When(x => { var get = x.PropClass; }).DoNotCallBase();
obj.PropClass.Returns(prop);

Now the explanation. NSubstitute records the calls made on a substitute, and when we call Returns, it grabs the last call made and tries to configure that to return a specific value.

What's happening when obj.PropClass.Returns(prop) runs is that the real obj.PropClass is called, which in turn calls obj.PropClasses, so NSubstitute now thinks obj.PropClasses is the last call. The Returns then tries to return a single PropClass when PropClasses expects an IEnumerable<PropClass>, hence the exception.

The fix above stops obj.PropClass from calling the base implementation immediately, so the last call does not get replaced with the PropClasses one and Returns can work as expected.

Admittedly this is quite awful, and one of the reasons we held out putting partial mocks into NSubstitute for so long. NSub's nice syntax comes at the price of it not always being able to distinguish when the developer is configuring a call from when real code needs to run. Sorry for the confusion.

like image 134
David Tchepak Avatar answered Oct 08 '22 22:10

David Tchepak