C#和Moq - 如何断言事件没有被提升

bar*_*rry 3 c# events unit-testing moq

我有一个应用程序,根据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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

如您所见,使用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"));
    }
Run Code Online (Sandbox Code Playgroud)

但它不起作用 - 在修复代码以确保不引发事件之前,测试总是通过.我甚至已经逐步完成了代码并观察到了异常被抛出Assert.Fail(),但是这不会导致测试失败,因为我的事件在try/catch块中引发并且捕获了NUnit异常.

有任何想法吗?

Ser*_*sev 5

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

  • @barry模式很简单:你将多线程移动到另一个模块(让我们称之为`dispatcher`),然后你测试你的`Sim`调用或不调用模拟的`dispatcher`(这一切都是同步发生的,所以很容易),你测试真正的`dispatcher`在调用时调度事件.在工作中分离关注点. (2认同)