How to properly unit test calling UI method on another thread?

感情迁移 提交于 2019-12-23 10:57:10

问题


Having coded an extension method (based on 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);
    }
}

I've been trying to unit test this method both from a UI thread and a normal thread and I can't seem to be able to achieve that.

Here is the unit test code:

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

The test passes but if I set a breakpoint in the InvokeEx method (not the call) I see that Control.InvokeRequired is false resulting in the func method directly called.

Furthermore, now the test fails because result is not set.

Additionally, while stepping through the code I see that the func method is executed on the other thread (as expected) and not on the main thread.

Maybe it is because I do not have a real UI thread since I am executing a unit test? How would I achieve that and all the message pumping?


回答1:


I've been trying different things and I've come up with the following:

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

This now works perfectly.

Note that I had to add an overload for InvokeEx for a void method.



来源:https://stackoverflow.com/questions/1362858/how-to-properly-unit-test-calling-ui-method-on-another-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!