Search code examples
c#nunitnsubstitute

Does NUnit re-instantiate classes marked as TestFixtures between each test?


I have a TestFixture marked class which is Unit testing the functionality of a class named 'HideCurrentTitleBarMessageTask'.

In this class I use a substitute to mock an interface in the [Setup] method, and in SOME tests in the test class I setup a return result from one of that mocked interfaces members.

[TestFixture]
public class TestClass_A {

    private ITitleBarMessageModel model;
    private ITitleBarMessage message;
    private HideCurrentTitleBarMessageTask task;
    private bool taskCompleteFired;


    [SetUp]
    public void SetUp() {
        taskCompleteFired = false;
        model = Substitute.For<ITitleBarMessageModel>();
        message = Substitute.For<ITitleBarMessage>();
        //model.currentlyDisplayedMessage = null;
        task = new HideCurrentTitleBarMessageTask();
        task.Init(model);
        task.Completed += (t) => { taskCompleteFired = true; };
    }

    [Test]
    public void Test_A() {
        task.Execute();
        Assert.That(taskCompleteFired, Is.True);
    }

    [Test]
    public void Test_B() {
        model.currentlyDisplayedMessage.Returns(message);
        task.Execute();
        message.Received(1).Hide();
        Assert.That(taskCompleteFired, Is.False);
    }
}

HideCurrentTitleBarMessageTask's Execute function looks like this

public override void Execute() {
        if (model.currentlyDisplayedMessage != null) {
            //Some irrelevant stuff
        } else {
            Completed(this);
        }
}

Notice that only in Test_B, do I setup a return value with model.currentlyDisplayedMessage.

If I breakpoint in line 1 of Test_A, I see in the debugger that model.currentlyDisplayedMessage is not null, but in fact assigned. When it shouldn't be. Even though presumably, the method SetUp was called prior, and the line

model = Substitute.For<ITitleBarMessageModel>();

was executed, effectively reassigning a new mocked instance to the model. This causes Test_A to fail.

Now, notice the commented out line

//model.curentlyDisplayedMessage = null;

in the SetUp method. Uncommenting this, fixes the issue by explicitly setting the reference in model to null. (I'm also assuming the same result could be achieved in a [TearDown] marked method).

Does NUnit not wipe out the TestClass and start from scratch in between tests?

If not, can anybody tell me why my call to

model = Substitute.For<ITitleBarMessageModel>();

in the SetUp() method hasn't provided me with a clean mocked instance of the model, to start my test with?


Solution

  • No, NUnit does not create a new instance of your fixture class for each test case. A single instance is created and then reused for each test. This is different from some other test frameworks but it is how NUnit has always worked (since 2000).

    The implication is that you have to be careful how you use the object state. 1. Use as little state as possible. 2. Use SetUp to initialize and TearDown to clean up.

    Per @David's comment... NSubstitute will automatically substitute for members that return interfaces. See Recursive mocks. I think this explains why model.currentlyDisplayedMessage is initialised for a freshly substituted model.