Тестирование управления 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 (что является основной причиной того, что вы должны выполнить такие тесты интеграции), что-то очень не так, и вы должны его исследовать.