3

我有一个应用程序,它根据 Sim 对象的状态引发事件。特别是,如果 Sim 的状态发生变化——即从 PinRequired 变为 Accessible——将引发 OnStatus 事件。事件通知新线程上的侦听器。

我在单元测试中使用 Moq 并且能够断言 OnStatus 是这样引发的:

        [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。

当我想断言没有引发事件时,我的困难就出现了。我不能使用 Monitor 等待事件不被引发,因为测试会永远等待!我可以在等待中添加超时,但这似乎是一个肮脏的黑客行为。

我尝试了以下方法:

        [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()了 .

有任何想法吗?

4

3 回答 3

5

简而言之,您不需要对多线程代码进行单元测试。您将其拆分为单线程部分并分别测试每个部分。

于 2012-09-15T15:40:35.460 回答
0

如果您也有 NoStatus 事件怎么办。

[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()
}
于 2012-09-15T15:05:58.347 回答
0

如何使用类似的东西:

mock.Verify(foo => foo.Execute("ping"), Times.Never());

您还可以验证是否已通过以下方式调用 OnStatus:

mock.Verify(foo => foo.Execute("ping"), Times.AtLeastOnce());

试试这个链接以获得很多好的简短示例:http ://code.google.com/p/moq/wiki/QuickStart

于 2012-09-15T15:40:07.413 回答