Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 976
Guy Joel McLean Avatar asked Apr 11 '17 15:04

Guy Joel McLean


People also ask

Does NUnit create a new instance for each test?

The fixture is created once for all of the tests in that fixture. For a given fixture class, a FixtureSetup method is run once for all of the tests in a fixture, and a Setup method is run once for each test.

Which attribute is used to mark the class for unit testing in NUnit?

The [TestFixture] attribute denotes a class that contains unit tests. The [Test] attribute indicates a method is a test method.

What is OneTimeSetUp in NUnit?

This attribute is to identify methods that are called once prior to executing any of the tests in a fixture. It may appear on methods of a TestFixture or a SetUpFixture. OneTimeSetUp methods may be either static or instance methods and you may define more than one of them in a fixture.

What is a TestFixture in NUnit?

In NUnit we have Test Fixtures containing Tests. A Test Fixture is the class that contain the tests we want to run. We typically write one test fixture for each class we want to test. As a convention we name the test fixture <Class to be tested>Tests.


1 Answers

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.

like image 130
Charlie Avatar answered Sep 22 '22 03:09

Charlie