Reputation: 4147
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
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
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
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