C#和Moq-如何断言未引发的事件
我有一个应用程序,它根据Sim对象的状态引发事件。特别是,如果Sim卡的状态发生变化(即从PIN Required变为Accessible),将引发OnStatus事件。这些事件通知新线程上的侦听器 我在单元测试中使用Moq,并且能够断言OnStatus是这样产生的:C#和Moq-如何断言未引发的事件,c#,unit-testing,events,moq,C#,Unit Testing,Events,Moq,我有一个应用程序,它根据Sim对象的状态引发事件。特别是,如果Sim卡的状态发生变化(即从PIN Required变为Accessible),将引发OnStatus事件。这些事件通知新线程上的侦听器 我在单元测试中使用Moq,并且能够断言OnStatus是这样产生的: [Test] public void TestOnStatusIsRaised() { Sim sim = new Sim(); sim.OnStatus += O
[Test]
public void TestOnStatusIsRaised()
{
Sim sim = new Sim();
sim.OnStatus += OnStatus;
lock (this)
{
sim.UpdateSimInfo(new Info("a new status"));
Monitor.Wait(this);
}
Assert.IsTrue(_onStatusCalled);
}
private void OnStatus(SimStatus obj)
{
lock (this)
{
_onStatusCalled = true;
Monitor.Pulse(this);
}
}
如您所见,使用Monitor类,我可以等到事件引发后再继续并断言_onStatusCalled标志已设置为true
当我想断言某个事件没有被提出时,我的困难就出现了。我不能使用监视器等待事件不被引发,因为测试将永远等待!我可以给等待加上一个超时,但这似乎是一个肮脏的黑客行为
我尝试了以下方法:
[Test]
public void TestOnStatusIsNotFired()
{
Sim sim = new Sim();
sim.OnStatus += onStatus => Assert.Fail("OnStatus Was called");
sim.UpdateSimInfo(new Info("the same status"));
}
但它不起作用-在修复代码以确保事件不会引发之前,测试总是通过。我甚至仔细检查了代码,发现Assert.Fail()
抛出了一个异常,但这不会导致测试失败,因为我的事件在try/catch块中引发,NUnit异常被捕获
有什么想法吗?如果你也为诺斯塔斯举办了一个活动呢
[Test]
public void TestOnStatusIsNotFired()
{
Sim sim = new Sim();
var mre = new ManualResetEvent(false);
sim.OnStatus += onStatus => { mre.Set(); Assert.Fail("OnStatus Was called");}
sim.NoStatus += () => { mre.Set();}
sim.UpdateSimInfo(new Info("the same status"));
mre.WaitOne()
}
使用类似于:
mock.Verify(foo => foo.Execute("ping"), Times.Never());
您还可以验证是否已通过以下方式调用OnStatus:
mock.Verify(foo => foo.Execute("ping"), Times.AtLeastOnce());
请尝试此链接以获得许多好的简短示例:简而言之,您不需要对多线程代码进行单元测试。您可以将其拆分为单线程部分,并分别测试每个部分。如果可能的话,我真的不想在应用程序代码中添加事件。此外,这仍然依赖于Assert.Fail()导致测试失败,而事实并非如此。这在多线程环境中是否可靠?我的意思是,在什么时候进行验证。在我们验证了onstatus没有被调用之后,是否有可能调用它?这将在我的测试中留下一个漏洞。我可以单元测试我的Sim对象是否正确更新-当然,必须有一个模式来测试观察者是否得到通知,即使它不被称为“单元测试”。@barry模式很简单:将多线程移动到另一个模块(我们称之为
调度程序),然后测试您的Sim
是否调用或不调用mock调度程序(这一切都是同步发生的,因此很容易),测试real调度程序在调用时是否调度事件。工作中的关注点分离。谢谢Serg,这听起来很有意义。您是否可以在完成要测试的代码循环时执行一个事件,并且当您收到该事件时,确保没有引发另一个事件?