Как правильно выполнить модульное тестирование вызова метода пользовательского интерфейса в другом потоке? - PullRequest
5 голосов
/ 01 сентября 2009

После кодирования метода расширения (на основе обновления графического интерфейса при запуске класса обработчика событий в отдельном потоке? ):

public static class ControlExtensions
{
    public static TResult InvokeEx<TControl, TResult> (this TControl control,
                                                       Func<TControl, TResult> func)
      where TControl : Control
    {
        if (control.InvokeRequired)
            return (TResult)control.Invoke (func, control);

        return func (control);
    }
}

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

Вот код модульного теста:

[Test]
public void TestInvokeExWithMethodReturningResultOnOtherThread ()
{
    // Prepare
    string result = string.Empty;
    var form = new Form ();
    var thread = new Thread (() =>
                             {
                                 result = form.InvokeEx (f => f.Text);
                             });

    // Execute
    thread.Start ();
    thread.Join (1000);

    // Verify
    Assert.That (result, Is.EqualTo ("Some label"));
}

Тест пройден, но если установить точку останова в методе InvokeEx (не вызов), я вижу, что Control.InvokeRequired имеет значение false, в результате чего func метод вызывается напрямую.

Кроме того, теперь тест не пройден, поскольку результат не установлен.

Кроме того, при пошаговом выполнении кода я вижу, что метод func выполняется в другом потоке (как и ожидалось), а не в основном потоке.

Может быть, это потому, что у меня нет реального потока пользовательского интерфейса, так как я выполняю модульный тест? Как мне добиться этого и прокачки всех сообщений?

1 Ответ

5 голосов
/ 01 сентября 2009

Я пробовал разные вещи и придумал следующее:

[Test]
public void TestInvokeExWithMethodReturningResultOnOtherThread ()
{
    // Prepare
    string result = string.Empty;
    var form = new Form ();
    var uiThread = new Thread (() => Application.Run (form));
    uiThread.SetApartmentState (ApartmentState.STA);
    uiThread.Start();
    Thread.Sleep (100);
    var thread = new Thread (() => result = form.InvokeEx (f => f.Text));

    // Execute
    thread.Start ();
    thread.Join ();
    form.InvokeEx (f => f.Close ());
    uiThread.Join ();

    // Verify
    Assert.That (result, Is.EqualTo ("Some label"));
}

Теперь это работает отлично.

Обратите внимание, что мне пришлось добавить перегрузку для InvokeEx для метода void.

...