UberFace
UberFace

Reputation: 485

NSubstitute use real instance of a class as substitute, except one method

Is there any built-in way in NSubstitute for mocking a class with its instance except for few methods?

In example I want to preserve the whole functionality of the instance, but check if a method gets called with particular parameters.

To do that actually I do

public class Wrapper: IInterface
{
    public IInterface real;
    public IInterface sub;

    public void Wrapper(IIterface realInstance, IIterface nsubstitute)
    {
        real = realInstance;
        sub = nsubstitute;
    }

    public void MethodThatShouldWorkAsAlways()
    {
        real.MethodThatShouldWorkAsAlways();
    }

    public intMethodToBeTested(int a)
    {
        return sub.MethodToBeTested();
    }
}

The reason for that is that I'm testing stuff complex enough that I can't simply create wrappers manually, that's time consuming and error-prone. It would be nice if Nsubstitute allows for something like:

IIterface realMock = NSubstitute.Mock< IIterface>( new RealClass());

realMock.MethodThatShouldWorkAsAlways(); // regular logic
realMock.MethodToBeTested(4).Returns( 3); // overrides the method to always returns 3

but I did not find any documentation for doing that so far.

Upvotes: 8

Views: 14557

Answers (1)

John Wright
John Wright

Reputation: 4597

If I'm understanding your situation correctly, you have a class you're testing which takes the IIterface as a dependency and you want to ensure the MethodToBeTested(int) method is being called by the class you're testing.

This can be done using the .ForPartsOf<T>() method of generating the mock. This generates a "partial mock", which will call the underlying class implementation unless you provide an override. It comes with a big requirement, though: The methods you want to override (or ensure were called) must be virtual (or abstract if defined in a base class).

Once you have the mock, then you can use .Received() to assert that methods on the mock were called (or not called, if you use .DidNotReceive()).

You don't actually need to override the behavior of MethodToBeTested(int) if you want the base implementation to be used.

Here's a concrete example, based on your sample code:

For the dependency, you have a RealClass that implements the interface IIterface and you want to ensure MethodToBeTested(int) was called. So those might look like this:

public interface IIterface
{
    void MethodThatShouldWorkAsAlways();
    int MethodToBeTested(int a);
}

public class RealClass: IIterface
{
    public void MethodThatShouldWorkAsAlways()
    { }

    public virtual int MethodToBeTested(int a)
    { return a; }
}

Then you have the class you're actually testing, which uses the IIterface as a dependency:

public class ClassThatUsesMockedClass
{
    private readonly IIterface _other;

    public ClassThatUsesMockedClass(IIterface other)
    {
        _other = other;
    }

    public void DoSomeStuff()
    {
        _other.MethodThatShouldWorkAsAlways();

        _other.MethodToBeTested(5);
    }
}

Now, you want to test that DoSomeStuff() actually calls MethodToBeTested(), so you'll need to create a partial mock of SomeClass and then use .Received() to validate it was called:

    [Test]
    public void TestThatDoSomeStuffCallsMethodToBeTested()
    {
        //Create your mock and class being tested
        IIterface realMock = Substitute.ForPartsOf<RealClass>();
        var classBeingTested = new ClassThatUsesMockedClass(realMock);

        //Call the method you're testing
        classBeingTested.DoSomeStuff();

        //Assert that MethodToBeTested was actually called
        realMock.Received().MethodToBeTested(Arg.Any<int>());

    }

Upvotes: 4

Related Questions