I have class which have one public method Start
, one private method and one event Finishing
. Start
call new Thread( private_method )
As mentioned you can unit test multi threaded components but it is not clean like regular unit tests. I have mostly encountered it in Acceptance Tests and have had great success with the .net 4 Task and Parallel classes. However in this case a simple sleep might get you going but if you start doing lots of these tests you might want a more performant way of doing it.
[Test]
public void Test1()
{
bool wasCalled = false;
SomeClass someObject = new SomeClass();
someObject.Finishing += new SomeClass.FinishingEventHandler((sender, a) =>
{
wasCalled = true;
});
someObject.Start(); // when this method will finish, then call event Finishing
Thread.Sleep(2000);
Assert.True(wasCalled);
}
What ever you do you need some timeout somewhere that will cause the test to finish instead of hanging forever, this could be done in the test itself or some test libraries have a Timeout attribute you can decorate the test with.
You are right.
First of all, NUnit and its various hosting environments had, or still have, various defects and limitations around threads started from within a test. In particular, if you do not make sure that the thread completes before the test execution is finished, then NUnit has no idea that someone is executing in code that it is going to unload after the test has returned. I remember this pattern regularly causing crashes of VS when NUnit was being executed from it via Resharper integration, as well as occasional glitches and memory leaks of the GUI and console runners provided with NUnit.
That said, you need to ensure two things.
Assert
all the various invariants.Even better, structure your code so that you can unit test it without background threads - if possible.
NUnit has built-in feature for waiting for assertion. It is called 'After':
[Test]
public void ShouldRaiseFinishedEvent()
{
SomeClass someObject = new SomeClass();
bool eventRaised = false;
someObject.SomethingFinished += (o, e) => { eventRaised = true; };
someObject.DoSomething();
Assert.That(eventRaised, Is.True.After(500));
}
[Test]
public void ShouldRaiseFinishedEvent()
{
SomeClass someObject = new SomeClass();
AutoResetEvent eventRaised = new AutoResetEvent(false);
someObject.SomethingFinished += (o, e) => { eventRaised.Set(); };
someObject.DoSomething();
Assert.IsTrue(eventRaised.WaitOne(TimeSpan.FromMilliseconds(500)));
}
This should work