Как написать асинхронный модульный тест WPF для метода, который использует Application.Current.Dispatcher.Invoke? - PullRequest
0 голосов
/ 13 ноября 2018

У нас есть приложение, написанное на WPF.Я пытаюсь написать модульный тест для некоторого кода, который работает в фоновых потоках.В нескольких местах этого кода нам нужно что-то делать в потоке пользовательского интерфейса.В этих местах мы используем следующую структуру кода:

Application.Current.Dispatcher.Invoke(new Action(() =>
{
// do something on UI thread
}));

Когда я создаю асинхронный модульный тест, кажется, что он застревает в методе Invoke.Я предполагаю, что это потому, что диспетчер не "отправляет".Я попытался исправить это с помощью класса DisaptcherUtil, на который ссылаются в ряде мест в Интернете.Но я не могу заставить это работать.Упрощенная версия моего кода теперь выглядит следующим образом:

    [TestMethod]
    public async Task TestDispatcher()
    {
        new Application();

        DispatcherUtil.DoEvents();

        await Task.Run(() => MethodUsingDispatcher());
    }


    private void MethodUsingDispatcher()
    {
        Application.Current.Dispatcher.Invoke(new Action(() =>
        {
            Console.WriteLine("On the dispatchee thread!");
        }));

        Console.WriteLine("BAck to background trhead");
    }

    public static class DispatcherUtil
    {
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        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)
        {
            Console.WriteLine("ExitFrame");

            ((DispatcherFrame)frame).Continue = false;
            return null;
        }
    }

Когда я запускаю тест под названием «TestDispatcher», он просто зависает.

У кого-нибудь есть идеи, почему это происходит?Это правильный способ сделать это, или я должен вместо этого пойти по пути создания интерфейса для Dispatcher, который я мог бы смоделировать в тестах.Я видел это сделано в некоторых местах.

1 Ответ

0 голосов
/ 13 ноября 2018

Я бы сказал, что вы должны скрыть диспетчеризацию за интерфейсом и смоделировать ее в модульных тестах:

interface IDispatcher
{
    void Dispatch(Action action);
}

Вы можете легко смоделировать это в своих тестах и ​​ожидать этих отправленных вызовов.

Реализация, которая использует настоящий диспетчер и может использоваться вашим приложением:

public class Dispatcher 
{
    public void Dispatch(Action action)
    {
        Application.Current.Dispatcher.Invoke(action);
    }
}
...