BackgroundWorker not working with TeamCity NUnit runner
I am using NUnit to test models in a WPF 3.5 application, and I am using a class BackgroundWorker
to execute asynchronous commands. unit test works fine with NUnit runner or ReSharper runner, but doesn't work on TeamCity 5.1.
How it is implemented:
I am using a ViewModel
named property IsBusy
and setting it to false on the event BackgroundWorker.RunWorkerCompleted
. In my test, I use this method to wait for the BackgroundWorker to finish:
protected void WaitForBackgroundOperation(ViewModel viewModel)
{
Console.WriteLine("WaitForBackgroundOperation 1");
int count = 0;
while (viewModel.IsBusy)
{
Console.WriteLine("WaitForBackgroundOperation 2");
RunBackgroundWorker();
Console.WriteLine("WaitForBackgroundOperation 3");
if (count++ >= 100)
{
Assert.Fail("Background operation too long");
}
Thread.Sleep(1000);
Console.WriteLine("WaitForBackgroundOperation 4");
}
}
private static void RunBackgroundWorker()
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
System.Windows.Forms.Application.DoEvents();
}
Well, sometimes it works and sometimes it hangs in the assembly. I suppose it is Application.DoEvents()
, but I don't know why ...
Edit: I added some traces (see code above) and in the log I have:
WaitForBackgroundOperation 1
WaitForBackgroundOperation 2
WaitForBackgroundOperation 2
WaitForBackgroundOperation 2
...
How is this possible ?!
a source to share
You run a set of background tasks, once a second. Move RunBackgroundWorker above the loop.
protected void WaitForBackgroundOperation(ViewModel viewModel)
{
Console.WriteLine("WaitForBackgroundOperation 1");
RunBackgroundWorker();
Thread.Sleep(100); // wait for thread to set isBusy, may not be needed
int count = 0;
while (viewModel.IsBusy)
{
Console.WriteLine("WaitForBackgroundOperation 2");
if (count++ >= 100)
{
Assert.Fail("Background operation too long");
}
Thread.Sleep(1000);
Console.WriteLine("WaitForBackgroundOperation 3");
}
}
private static void RunBackgroundWorker()
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
DoEvents is not required.
a source to share