views:

746

answers:

2

This test fails when it is run with the NUnit console runner. It works if I run just that test with TestDriven.NET, but not if I run the entire suite with TestDriven.NET:

[Test]
public void BackgroundWorkerFiresRunWorkerCompleted()
{
  var runner = new BackgroundWorker();
  ManualResetEvent done = new ManualResetEvent(false);
  runner.RunWorkerCompleted += delegate { done.Set(); };

  runner.RunWorkerAsync();

  bool res = done.WaitOne(TimeSpan.FromSeconds(10));
  // This assert fails:
  Assert.IsTrue(res, "RunWorkerCompleted was not executed within 10 seconds");
}

I suspect the problem have something to do with not having a message-loop, but I am not sure.

What are the requirements for using BackgroundWorker?

Is there a workaround to make the test work?

A: 

Are you missing a BGW DoWork event handler?

Noel Kennedy
The actual class I want to test subclasses BackgroundWorker and overrides OnDoWork(). But it makes no difference if I add a DoWork event-handler. The RunWorkerCompleted event-handler is still not run.
Rasmus Faber
+6  A: 

I don't think that it has to do with the message pump, since tests usually run in a blocking fashion anyways. But it may be that the event is invoked on the "UI" thread, which uses a windows message which does not get handled.

So, if the problem was the message pump or windows messages not being handled, you could try like this to replace your current bool res = done.WaitOne(TimeSpan.FromSeconds(10)); line:

DateTime end = DateTime.Now.AddSeconds(10);
bool res = false;
while ((!res) && (DateTime.Now<end)) {
   Application.DoEvents();
   res = done.WaitOne(0):
}
Lucero
That works. Thanks!
Rasmus Faber
We've found DoEvents() is only required when the test (or a previous test in the same test run) instantiates a Windows form or control. Why?
Brian
Because for any WinForms control, window messages need to be passed through the message pump, which doesn't happen if you don't call `DoEvents()`.
Lucero