nirmus
nirmus

Reputation: 5103

testing method which create a new thread and result we get from event ( NUnit 2.6 )

I have class which have one public method Start, one private method and one event Finishing. Start call new Thread( private_method ). Private method return value using event. When this method finish their work, then call this event.

Now I want to write test to this class. If I write it like this:

    [Test]
    public void Test1()
    {
        SomeClass someObject = new SomeClass();

        someObject.Finishing += new SomeClass.FinishingEventHandler((sender, a) =>
        {
            Assert.True(false);
        });
        someObject.Start(); // when this method will finish, then call event Finishing
    }

It should be fail, but it isn't. I think that method Test1 is finished before event is raised. So, how can I test this code? How test method, which create a new thread, and result we get from event

Upvotes: 5

Views: 4938

Answers (4)

Jeba Ranganathan
Jeba Ranganathan

Reputation: 582

[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

Upvotes: 2

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236238

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

Upvotes: 18

Bronumski
Bronumski

Reputation: 14272

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.

Upvotes: 0

Jirka Hanika
Jirka Hanika

Reputation: 13529

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.

  1. Elementary safety of the test environment by joining all the threads that you spawn.
  2. Throwing all exceptions that indicate test failure on the main thread only. This means that the background thread has to communicate its results to the main thread, and that one has to Assert all the various invariants.

Even better, structure your code so that you can unit test it without background threads - if possible.

Upvotes: 1

Related Questions