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 被初始化为新替换的模型。
我有一个标记为 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 被初始化为新替换的模型。