Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#和Moq-如何断言未引发的事件_C#_Unit Testing_Events_Moq - Fatal编程技术网

C#和Moq-如何断言未引发的事件

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

我有一个应用程序,它根据Sim对象的状态引发事件。特别是,如果Sim卡的状态发生变化(即从PIN Required变为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

当我想断言某个事件没有被提出时,我的困难就出现了。我不能使用监视器等待事件不被引发,因为测试将永远等待!我可以给等待加上一个超时,但这似乎是一个肮脏的黑客行为

我尝试了以下方法:

        [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,这听起来很有意义。您是否可以在完成要测试的代码循环时执行一个事件,并且当您收到该事件时,确保没有引发另一个事件?