Тестирование номеров NMOCK против WPF и диспетчера
-
30-09-2019 - |
Вопрос
Вот один для резьбовых наркоманов там. У меня этот метод:
public void RefreshMelts()
{
MeltsAvailable.Clear();
ThreadPool.QueueUserWorkItem(delegate
{
Dispatcher.BeginInvoke((ThreadStart)delegate
{
eventAggregator.GetEvent<BusyEvent>().Publish(true);
eventAggregator.GetEvent<StatusMessageEvent>().Publish(
new StatusMessage("Loading melts...", MessageSeverity.Low));
});
try
{
IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts();
Dispatcher.Invoke((ThreadStart)delegate
{
foreach (MeltDto availableMelt in meltDtos)
{
MeltsAvailable.Add(availableMelt);
}
OnPropertyChanged("MeltsAvailable");
eventAggregator.GetEvent<BusyEvent>().Publish(false);
eventAggregator.GetEvent<StatusMessageEvent>().Publish(
new StatusMessage("Melts loaded", MessageSeverity.Low));
});
}
catch (ApplicationException ex)
{
log.Error("An error occurred in MeltsViewModel when attempting to load melts", ex);
Dispatcher.Invoke((ThreadStart)delegate
{
MeltsAvailable.Clear();
eventAggregator.GetEvent<StatusMessageEvent>().Publish(
new StatusMessage("Melt data could not be loaded because an error occurred; " +
"see the application log for detail",
MessageSeverity.High));
eventAggregator.GetEvent<BusyEvent>().Publish(false);
});
}
});
}
Это определяется в контроле пользователей WPF. MeltsAvailable - это наблюдательное оборудование мельтдос. Этот код красиво работает при запуске в самом приложении.
Беда в том, что я хотел бы создать тест на единицу, используя NMock, чтобы проверить результаты этого метода - в частности, что после того, как он называется, мельциавственное свойство имеет некоторые элементы. Вот метод теста:
[TestMethod]
public void GetAvailableMeltsTest()
{
MeltDto mockMelt1 = new MeltDto();
MeltDto mockMelt2 = new MeltDto();
mockMelt1.MeltIdentifier = "TST0001";
mockMelt2.MeltIdentifier = "TST0002";
IList<MeltDto> availableMelts = new List<MeltDto>();
availableMelts.Add(mockMelt1);
availableMelts.Add(mockMelt2);
Expect.Exactly(1).On(service).Method("GetActiveMelts").Will(Return.Value(availableMelts));
MeltsViewModel vm = new MeltsViewModel(aggregator, logger, service, configManagerFactory); // All of these are mock objects
vm.RefreshMelts();
Thread.Sleep(millisecondDelayForEventPublish * 100);
mockery.VerifyAllExpectationsHaveBeenMet();
Assert.AreEqual(vm.MeltsAvailable.Count, 2);
Assert.AreEqual(vm.MeltsAvailable[0].MeltIdentifier, "TST0001");
Assert.AreEqual(vm.MeltsAvailable[1].MeltIdentifier, "TST0002");
}
Тест последовательно не удается на первом утверждении.Areequal. VM.meltsavailable в этом точке пусто.
Если я откроющуюся всю нить и оставьте это как:
public void RefreshMelts()
{
MeltsAvailable.Clear();
IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts();
foreach (MeltDto availableMelt in meltDtos)
{
MeltsAvailable.Add(availableMelt);
}
OnPropertyChanged("MeltsAvailable");
}
Тестовые проходит.
Итак, очевидно, есть что-то, что оно не нравится в темах - но даже поворачиваясь от отладки-> исключения-> CLR исключения -> бросить, а выключение только моего кода, я не получаю никаких исключений вообще в обновлениях.
Саманная часть заключается в том, что Dispatcher.invoke вызовите, где я загружаю объекты Meltdto в коллекцию мельца в мельцаверющую, кажется, не вызывают. Я могу одеться весь раздел с точками останова, и они никогда не попадают. Усиление нити. Время в моем тесте даже до десяти секунд ничего не меняется.
Почему? Почему этот раздел не выполняется, почему я не могу войти в него или ломаться в него, почему я не получаю исключения, почему он работает нормально в исполнении, но не в тесте?
Спасибо большое, Стив
Решение
Диспетчер - это цикл сообщений, который привязан к выполнению потока. Это обрабатывает элементы в очередь, когда основной нить простаивается. В тесте подразделения, которое никогда не происходит. Нить занята, а затем выходит, когда тест завершен.
Если вы используете Visual Studio, чтобы запустить тесты, вы можете включить подсветку покрытия кода, и вы увидите, что код внутри Dispatcher.invoke () никогда не вызывается (он будет отображаться красным).
DispatcherFrame можно использовать для запуска диспетчера для обработки по очереди сообщений. Добавьте следующий класс помощника в свой модульный тестовый проект:
public static class DispatcherHelper
{
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
В конце вашего теста (до утверждений) Вызов DispatcherHelperhelper.Dovents (). Это заставит диспетчера для обработки выдающихся событий, таких как те, которые добавляют элементы к наблюдаемой коллекции смотровой модели. Затем вы можете проверить свойства модели зрения, чтобы убедиться, что они были установлены правильно.