DEV Community

Alex Khanuckaev
Alex Khanuckaev

Posted on

Using NSubstitute to implement multiple interfaces

NSubstitute is an invaluable tool for .NET developers, offering a streamlined approach to creating test doubles for complex systems. It can easily create mocks not only for interfaces, but also for object. It has quite intelligible documentation, but some of their use cases are not fully covered. Inheritance of multiple interfaces, for example.

Creating Substitutes for Multi-Interface Objects with NSubstitute

NSubstitute provides a seamless way to create substitutes for objects that implement multiple interfaces. Let's explore the steps involved in this process.

Step 1: Define the Interfaces

First, define the interfaces that the object implements. For example, consider an object that implements IFoo and IBar interfaces.

    public interface IFoo
    {
        string FooMethod();
    }

    public interface IBar
    {
        string BarMethod();
    }
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a substitute

NSubstitute allows you to specify multiple interfaces when creating a substitute:

var multiInterfaceSubstitute = Substitute.For<IFoo, IBar>();
var substitute = Substitute.For<IFoo, IBar>();
Assert.True(substitute is IFoo);
Assert.True(substitute is IBar);
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure the Behavior

To configure substitute behaviour you can try use it as you always do:

substitute.FooMethod().Returns("Foo response");
substitute.BarMethod().Returns("Bar response");
Enter fullscreen mode Exit fullscreen mode

No. This wouldn’t compile:

Image description

C# compiler is absolutely sure, that your object substitute is only type of IFoo. But not an IBar. I spent some time pondering around this error and was ready to just implement interface that inherits them both. But maybe I wasn’t the first person in the world who encounter this? Unfortunately, Google, StackOverflow and even bing didn’t give me the answer, but with some testing and trying I got this elegant (no) solution:

substitute.FooMethod().Returns("Foo!");
((IBar)substitute).BarMethod().Returns("Bar!");

Assert.Equal("Bar!", ((IBar)substitute).BarMethod());
Enter fullscreen mode Exit fullscreen mode

Other things to play around:

You can implement one known class and set of interfaces there:

[Fact]
public void Test2()
{
    var substitute = Substitute.For<MyClass, IFoo, IBar>()!;
    Assert.True(substitute is IBar);
    ((IBar)substitute).BarMethod().Returns("Bar!");

    Assert.Equal("Bar!", ((IBar)substitute).BarMethod());
}
Enter fullscreen mode Exit fullscreen mode

Let’s try it with classes.

var substitute = Substitute.For<MyClass, NotMyClass>()!;
Enter fullscreen mode Exit fullscreen mode

This doesn’t work and raises the exceptions:

Tests.UnitTest1.Test4 (< 1ms): Error Message: NSubstitute.Exceptions.SubstituteException : Can not substitute for multiple classes. To substitute for multiple types only one type can be a concrete class; other types can only be interfaces.

So, unfortunately for some c++ folks, there is no multiple inheritance here.

Follow me on Medium

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay