Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: How to test a basic threaded worker class

I'm dipping my toes in how to test multi-threaded stuff, but not quite sure how to get started. I'm sure I will figure more stuff out easier if I could just get stuff going, so I was wondering if someone could help me write an NUnit test case for this simple class:

class Worker
{
    public event EventHandler<EventArgs> Done = (s, e) => { };

    public void StartWork()
    {
        var thread = new Thread(Work) { Name = "Worker Thread" };
        thread.Start();
    }

    private void Work()
    {
        // Do some heavy lifting
        Thread.Sleep(500);
        Done(this, EventArgs.Empty);
    }
}

What I would like to test is simply: Is the Done event raised when it finishes. I would have no problems if it was synchronous, but not sure where to even begin when it is not. A simple test if it wasn't multi-threaded (and the Work method wasn't private) could be:

[TestFixture]
class WorkerTests
{
    [Test]
    public void DoWork_WhenDone_EventIsRaised()
    {
        var worker = new Worker();

        var eventWasRaised = false;
        worker.Done += (s, e) => eventWasRaised = true;

        worker.Work();
        Assert.That(eventWasRaised);
    }
}

Any pointers?

like image 388
Svish Avatar asked Nov 20 '09 14:11

Svish


2 Answers

You need to use a ManualResetEvent - see Unit Testing Multi-Threaded Asynchronous Events for more details.

Something like:

[Test]
public void DoWork_WhenDone_EventIsRaised()
{
   var worker = new Worker();

   var eventWasRaised = false;
   var mre = new ManualResetEvent(false);
   worker.Done += (s, e) => { eventWasRaised= true; mre.Set(); };

   worker.Work();
   mre.WaitOne(1000);
   Assert.That(eventWasRaised);
}
like image 109
mcintyre321 Avatar answered Sep 29 '22 23:09

mcintyre321


The main problem you find with testing threaded apps is actually stimulating the thread with test data because you will need to block on the main thread to wait until the other thread exits.

The way we've worked with this is to test it synchronously as you suggest. This allows you to test the logical behaviour but it won't detect deadlocks and race conditions of course (not that testing can assert these things easily anyway).

like image 42
Matt Breckon Avatar answered Sep 30 '22 01:09

Matt Breckon