【问题标题】:How to properly unit test calling UI method on another thread?如何在另一个线程上正确地对调用 UI 方法进行单元测试?
【发布时间】:2010-11-24 16:09:44
【问题描述】:

编写了扩展方法(基于GUI update when starting event handler class on separate thread?):

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);
    }
}

我一直在尝试从 UI 线程和普通线程对这个方法进行单元测试,但我似乎无法实现。

单元测试代码如下:

[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 方法直接调用。

此外,现在测试失败了,因为 result 没有设置。

此外,在单步执行代码时,我看到 func 方法在另一个线程(如预期)上执行,而不是在主线程上。

也许是因为我在执行单元测试时没有真正的 UI 线程?我将如何实现这一点以及所有的消息传递?

【问题讨论】:

    标签: .net multithreading unit-testing c#-3.0 nunit


    【解决方案1】:

    我一直在尝试不同的事情,我想出了以下几点:

    [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"));
    }
    

    现在完美运行。

    请注意,我必须为 void 方法添加 InvokeEx 的重载。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-24
      相关资源
      最近更新 更多