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?
In short, you don’t unit-test multi-threading code. You split it into single-threaded parts and test each one separately.