Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 448
UberFace Avatar asked Apr 17 '18 16:04

UberFace


People also ask

How do you mock static class in NSubstitute?

NSubstitute can't mock static methods, so if you want to use NSub for this you'll need to rewrite the original class, or wrap the functionality in a new class that you can mock.

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. Product.

Which is the basic syntax for creating a substitute?

The basic syntax for creating a substitute is: var substitute = Substitute. For<ISomeInterface>(); This is how you'll normally create substitutes for types.


1 Answers

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>());

    }
like image 63
John M. Wright Avatar answered Sep 28 '22 04:09

John M. Wright