Тестирование управления WPF без добавления его в окно
У меня есть UserControl
, который публикует сообщение EventAggregator
в своем Loaded
событии. Чтобы проверить это (и получить событие Loaded
), я в настоящее время создаю окно и добавляю к нему элемент управления, а затем ожидаю, когда событие Loaded
будет поднято.
Есть ли способ настроить тест, чтобы событие Loaded
срабатывало без необходимости создания и добавления элемента управления в окно?
Например:
[Test, RequiresSTA]
public void active_thingy_message_is_published_on_loaded()
{
const string TestMsg = "Active thingy changed";
using (AutoResetEvent loadedEvent = new AutoResetEvent(false))
{
DummyEventService eventService = new DummyEventService();
DummyControl control = new DummyControl(eventService, TestMsg);
control.Loaded += delegate { loadedEvent.Set(); };
Assert.That(eventService.Message, Is.Null, "Before.");
Window window = new Window { Content = control };
window.Show();
loadedEvent.WaitOne();
window.Dispatcher.InvokeShutdown();
Assert.That(eventService.Message, Is.EqualTo(TestMsg), "After.");
}
}
private class DummyControl : UserControl
{
public DummyControl(DummyEventService eventService, string testMsg)
{
Loaded += delegate { eventService.Publish(testMsg); };
}
}
private class DummyEventService
{
public string Message { get; private set; }
public void Publish(string msg) { Message = msg; }
}
Обновление
Я изменил название с "Unit Testing..." на "Testing..." и заменил тег "unit-testing" на "тестирование".
Я бы предпочел не разделить волосы на то, какой класс теста это, так как он не является конструктивным. Да, можно утверждать, что это не "Unit Test", но это не полезно. Я хочу проверить проблему, зависящую от жизненного цикла элемента управления, и это связано с событием Loaded
. Это важный регрессионный тест, поскольку сторонние компоненты, которые я не контролирую, зависят от сообщения, которое создается в Loaded
.
Может ли событие Loaded
быть поднято без добавления элемента управления в окно?
Ответы
Ответ 1
Если вас просто интересует стрельба по событию Loaded целевого элемента управления, то Reflection должен сделать трюк.
public static void RaiseLoadedEvent(FrameworkElement element)
{
MethodInfo eventMethod = typeof(FrameworkElement).GetMethod("OnLoaded",
BindingFlags.Instance | BindingFlags.NonPublic);
RoutedEventArgs args = new RoutedEventArgs(FrameworkElement.LoadedEvent);
eventMethod.Invoke(element, new object[] { args });
}
Это буквально запускает метод OnLoaded, который присутствует в каждом элементе FrameworkElement, поэтому, если ваш тест требует состояния приложения, это не сработает.
Кроме того, нет никакой связи между событием Loaded родителя и его дочерними элементами. Если для проверки требуется, чтобы дочерние элементы запускали свои события Loaded, тогда вспомогательный метод должен вручную перемещать дочерние элементы управления и запускать их также.
Ответ 2
За последние два года, возможно, все изменилось. Для покрытия кода я столкнулся с этой проблемой, и это решение.
WPF UIElements наследует метод RaiseEvent, который принимает RoutedEventArgs. Это может быть построено с использованием конкретного UIElement.LoadedEvent, позволяющего получить этот последний бит покрытия кода.
Я сомневаюсь, что вам все еще нужен мой ответ, но кто-то может.
Ответ 3
Рефакторинг, что в обработчике события Loaded
в свой собственный метод, и обработчик события Loaded
вызывает его. Напишите unit test, чтобы проверить метод refactored, а не событие Loaded
.
Тестирование модулей проверяет, что блок выполняет то, что он должен делать. Тестирование того, как устройство взаимодействует с другими модулями, - это интеграционное тестирование. Это, безусловно, полезно для проведения тестирования интеграции и для возможности интеграции интегрированных модулей регрессионного тестирования, но это другая задача от модульного тестирования.
Наконец: если у вас нет уверенности в том, что при его загрузке запускается событие управления Loaded
(что является основной причиной того, что вы должны выполнить такие тесты интеграции), что-то очень не так, и вы должны его исследовать.