We try to automate test over some old legacy code. There is a form which opens, run the timer and read data from port. The unittest open the form, but the timer does not tick until Application.DoEvents start process the process the windows message queue. It is different because it is execute from unittest and Application.Run is not the part of code.
But we cannot block unittest thread by Application.DoEvents, because we need to wait and check data by assert.
ThreadPool.QueueUserWorkItem(x =>
{
While(!form.workFinished)
{
Application.DoEvents();
Thread.Sleep(50);
}
synchronization.Set();
});
synchronization.WaitOne();
Assert.AreEqual(10000, form.recorded.Count);
But this snippet is not doing what I would expect. It is different than executing the form from WinForm App? Can I call Application.DoEvents from threadpool?
I really don't want really not modify the legacy code. I just need to get unittest working over current solution.
The best way to do this is to run the form normally using Application.Run. When the test is done close the form or call Application.Exit on that thread.
DoEvents
pumps events on the current thread. There can be multiple UI threads. DoEvents
only affects the current one.
Your your unit test code could look like:
Form form = null;
var task = Task.Factory.StartNew(() => {
form = new Form(); //Run ctor on UI thread.
Application.Run(form);
}, LongRunning);
//Work with the form here.
form.Invoke(() => Application.Exit());
task.Wait();
This is just a sketch. Synchronization is missing and I'm sure there are other things left to solve for you.
LongRunning
ensures that the GUI runs on a fresh thread each time. This prevents state leaks from test to test.
Basically, this is the standard UI thread plus worker thread model. Here, the unit test thread is the worker and the UI thread needs to be created. Normally, the UI thread would be the Main
thread and the worker would be created.