简体   繁体   中英

C# and Moq - How to Assert an Event is Not Raised

I have an application that raises events depending on the state of a Sim object. In particular, if the state of the Sim changes - ie from PinRequired to Accessible - an OnStatus event will be raised. The events notify listeners on a new thread.

I am using Moq in my unit tests and am able to assert that OnStatus is raised like so:

        [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);
        }
    }

As you can see, using the Monitor class I can wait until the event is raised before proceeding and asserting that the _onStatusCalled flag has been set to true.

My difficulty arises when I want to assert that an event is not raised. I can't use Monitor to wait for the event not to be raised as the test would wait forever! I could added a timeout to the wait, but that seems like a dirty hack.

I have tried the following:

        [Test]
    public void TestOnStatusIsNotFired()
    {
        Sim sim = new Sim();
        sim.OnStatus += onStatus => Assert.Fail("OnStatus Was called");

        sim.UpdateSimInfo(new Info("the same status"));
    }

but it doesn't work - before fixing the code to ensure the event is not raised, the test always passes. I have even stepped through the code and observed an exception being thrown by the Assert.Fail() , but this does not cause the test to fail as my event is raised in a try/catch block and the NUnit exception is caught.

Any ideas?

In short, you don't unit-test multi-threading code. You split it into single-threaded parts and test each one separately.

What if you had an event for NoStatus also.

[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()
}

How about using something like:

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

You can also verify that OnStatus has been called with:

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

try this link for lots of good short samples: http://code.google.com/p/moq/wiki/QuickStart

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM