NUnit 是否在每次测试之间重新实例化标记为 TestFixtures 的 类?

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

我有一个标记为 class 的 TestFixture,它正在对名为 'HideCurrentTitleBarMessageTask' 的 class 的功能进行单元测试。

在这个 class 中,我使用替代方法在 [Setup] 方法中模拟接口,并且在测试 class 的一些测试中,我设置了一个 return 结果那些模拟接口成员。

[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 的执行函数如下所示

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

请注意,只有在 Test_B 中,我才使用 model.currentlyDisplayedMessage.

设置 return 值

如果我在 Test_A 的第 1 行断点,我会在调试器中看到 model.currentlyDisplayedMessage 不是 null,但实际上已分配。在不应该的时候。尽管据推测,方法 SetUp 之前被调用过,并且行

model = Substitute.For<ITitleBarMessageModel>();

已执行,有效地将新的模拟实例重新分配给模型。 这会导致 Test_A 失败。

现在,注意注释掉的行

//model.curentlyDisplayedMessage = null;

在 SetUp 方法中。取消注释,通过将模型中的引用显式设置为 null 来解决问题。 (我还假设在 [TearDown] 标记的方法中可以实现相同的结果)。

NUnit 不会在测试之间清除 TestClass 并从头开始吗?

如果没有,谁能告诉我为什么我打电话给

model = Substitute.For<ITitleBarMessageModel>();

在 SetUp() 方法中没有为我提供一个干净的模拟模型实例,以开始我的测试?

不,NUnit 不会为每个测试用例创建夹具的新实例 class。创建单个实例,然后将其重新用于每个测试。这与其他一些测试框架不同,但这是 NUnit 一直以来的工作方式(自 2000 年以来)。

言外之意是你必须小心使用对象状态。 1、尽量少用state。 2. 使用SetUp 初始化和TearDown 清理。

根据@David 的评论...NSubstitute 将自动替换 return 接口的成员。请参阅递归模拟。我认为这解释了为什么 model.currentlyDisplayedMessage 被初始化为新替换的模型。