Guy*_*ean 5 c# nunit nsubstitute
我有一个 TestFixture 标记的类,它是对名为“HideCurrentTitleBarMessageTask”的类的功能进行单元测试。
在这个类中,我使用一个替代来模拟 [Setup] 方法中的一个接口,并且在测试类中的一些测试中,我设置了一个来自模拟接口成员的返回结果。
[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);
}
}
Run Code Online (Sandbox Code Playgroud)
HideCurrentTitleBarMessageTask 的 Execute 函数如下所示
public override void Execute() {
if (model.currentlyDisplayedMessage != null) {
//Some irrelevant stuff
} else {
Completed(this);
}
}
Run Code Online (Sandbox Code Playgroud)
注意,只有Test_B,做我的设置有一个返回值model.currentlyDisplayedMessage。
如果我在 Test_A 的第 1 行断点,我会在调试器中看到model.currentlyDisplayedMessage不为空,但实际上已分配。不应该的时候。即使可以推测,方法SetUp之前被调用,并且该行
model = Substitute.For<ITitleBarMessageModel>();
Run Code Online (Sandbox Code Playgroud)
被执行,有效地将一个新的模拟实例重新分配给模型。这会导致 Test_A 失败。
现在,注意注释掉的行
//model.curentlyDisplayedMessage = null;
Run Code Online (Sandbox Code Playgroud)
在设置方法中。取消注释,通过将模型中的引用显式设置为空来解决问题。(我还假设在 [TearDown] 标记的方法中可以实现相同的结果)。
NUnit 不会清除 TestClass 并在两次测试之间从头开始吗?
如果没有,谁能告诉我为什么我打电话给
model = Substitute.For<ITitleBarMessageModel>();
Run Code Online (Sandbox Code Playgroud)
在 SetUp() 方法中没有为我提供模型的干净模拟实例,以开始我的测试?
不,NUnit 不会为每个测试用例创建一个新的夹具类实例。创建单个实例,然后为每个测试重用。这与其他一些测试框架不同,但它是 NUnit 一直工作的方式(自 2000 年以来)。
这意味着您必须小心使用对象状态的方式。1.尽量少用state。2.使用SetUp进行初始化,使用TearDown进行清理。
根据@David 的评论... NSubstitute 将自动替换返回接口的成员。请参阅递归模拟。我认为这解释了为什么 model.currentlyDisplayedMessage 是为新替换的模型初始化的。