NSubstitute’s unexpected default return value

NSubstitute is a great tool when You are writing unit tests for Your product which was designed with dependency injection in mind.

Let’s see it:

    public interface IWorker
    {
        object GetResult();
    }

    [TestMethod]
    public void ExecuterTest_WorkerCalledOrNot()
    {
        var workerSubstitute = Substitute.For<IWorker>();

        var executerToTest = new Executer(workerSubstitute);

        // we test here
        executerToTest.Execute();

        workerSubstitute.Received(1).GetResult();
    }

In the code above I was not interested in the real value of the worker’s result. I wanted only to know whether the worker’s GetResult method gets called or not. But all of my workers do some hard work, so for this test I dont want to instantiate them and implicitli convert my unit test into integration test. So I create a substitute via NSubstitute for the given interface and gave that to my Executer.

The substitute tries to be as neutral as it can be. All void methods return asap, all non void methods return the default value for the return type. Naturally You can modify that behaviour and explicitly tell the substitute what to do when it’s methods get called, so You can for example redirect all database calls to in memory data structures during tests if You created Your DAL layer with DI in mind. And meanwhile the subtitute collects data about its use, so we can ask it whether it was called or not and with what arguments, etc.

But today I found got something unexpected thing.

Change a bit the example above to demonstrate it:

    public interface IWorker
    {
        TRet GetResult<TRet>();
    }

    [TestMethod]
    public void SubstituteReturnValueTest()
    {
        var workerSubstitute = Substitute.For<IWorker>();

        // test #1
        var r1 = workerSubstitute.GetItem<int>();
        Assert.AreEqual(default(int), r1);

        // test #2
        var r2 = workerSubstitute.GetItem<List<int>>();
        Assert.AreEqual(default(List<int>), r2);

        // test #3
        var r3 = workerSubstitute.GetItem<IList<int>>();
        Assert.AreEqual(default(IList<int>), r3);
    }

This will fail at Assert of test #3 because r3 wont be null as You would expect but an instance of “Castle.Proxies.IList`1Proxy”!

I think it is a bug but may be a result of some design decisions which priorized some functionality (retval is an instance of some interface which is wrapped around with a subtitute created on the fly) over coherency.

So be careful 🙂

This entry was tagged , .

Leave a Reply