barry
barry

Reputation: 4147

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 - i.e. 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?

Upvotes: 3

Views: 3052

Answers (3)

Sergei Rogovtcev
Sergei Rogovtcev

Reputation: 5832

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

Upvotes: 5

JTMon
JTMon

Reputation: 3199

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

Upvotes: 0

Dharun
Dharun

Reputation: 613

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

Upvotes: 0

Related Questions