Вызывает ли Application.DoEvents в основном потоке то же, что и в ThreadPool?
Мы пытаемся автоматизировать тестирование старого устаревшего кода. Есть форма, которая открывается, запускает таймер и читает данные из порта. Юнит-тест открывает форму, но таймер не ставится до тех пор, пока Application.DoEvents не запустит процесс обработки очереди сообщений Windows. Он отличается тем, что выполняется из unittest, а Application.Run не является частью кода.
Но мы не можем заблокировать поток unittest с помощью Application.DoEvents, потому что нам нужно подождать и проверить данные с помощью assert.
ThreadPool.QueueUserWorkItem(x =>
{
While(!form.workFinished)
{
Application.DoEvents();
Thread.Sleep(50);
}
synchronization.Set();
});
synchronization.WaitOne();
Assert.AreEqual(10000, form.recorded.Count);
Но этот фрагмент не делает то, что я ожидал. Это отличается от выполнения формы из приложения WinForm? Могу ли я вызвать Application.DoEvents из пула потоков?
Я действительно не хочу на самом деле не изменять старый код. Мне просто нужно, чтобы unittest работал над текущим решением.
1 ответ
Лучший способ сделать это - запустить форму в обычном режиме с помощью Application.Run. Когда тест завершен, закройте форму или вызовите Application.Exit в этом потоке.
DoEvents
качает события в текущем потоке. Там может быть несколько потоков пользовательского интерфейса. DoEvents
влияет только на текущий.
Ваш код модульного теста может выглядеть так:
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();
Это всего лишь эскиз. Синхронизация отсутствует, и я уверен, что есть другие вещи, которые нужно решить для вас.
LongRunning
гарантирует, что GUI работает на новом потоке каждый раз. Это предотвращает утечки состояния из теста в тест.
По сути, это стандартный поток пользовательского интерфейса плюс модель рабочего потока. Здесь поток модульного тестирования является рабочим, и необходимо создать поток пользовательского интерфейса. Обычно поток пользовательского интерфейса будет Main
нить и рабочий будет создан.