How can I unit test async methods on the UI Thread

2019-08-03 22:30发布

I have successfully been able to get the following nested async unit test working using TouchRunner (NUnitLite) in Xamarin:

[Test]
[Timeout (Int32.MaxValue)]
public async void NestedAsyncFail()
{
    await Task.Run(async() =>
    {
        await Task.Delay(1000);
    });

    Assert.AreEqual(1, 0);
}

[Test]
[Timeout (Int32.MaxValue)]
public async void NestedAsyncSuccess()
{
    await Task.Run(async() =>
    {
        await Task.Delay(1000);
    });

    Assert.AreEqual(1, 1);
}

Results: http://i.stack.imgur.com/5oC11.png

However, what if I want to test an async method that needs to perform some logic but also make some UI changes and thus, be executed on the main thread? Below is my attempt at doing this however, there are some issues...

[Test]
[Timeout (Int32.MaxValue)]
public void TestWithUIOperations()
{
    bool result = false;

    NSObject invoker = new NSObject ();
    invoker.InvokeOnMainThread (async () => {
        await SomeController.PerformUIOperationsAsync ();
        result = true;
    });

    Assert.True (result);
}

With the Timeout attribute the TouchRunner freezes probably due to some thread locking. Without the Timeout attribute, the assertion returns false - I believe this is due to the async method not awaiting properly?

Can anyone advise where I'm going wrong and/or how this can be accomplished?

My use of the Timeout attribute in the first test is explained here: https://bugzilla.xamarin.com/show_bug.cgi?id=15104

1条回答
We Are One
2楼-- · 2019-08-03 23:03

I've used an AutoResetEvent in situations like these to test our asynchronous startup routines:

[Test]
public void CanExecuteAsyncTest()
{
    AutoResetEvent resetEvent = new AutoResetEvent(false);
    WaitHandle[] handles  = new WaitHandle[] { resetEvent};

    bool success = false;

    Thread t = new Thread(() => {
        Thread.Sleep(1000);
        success = true;
        resetEvent.Set();
    });

    t.Start ();

    WaitHandle.WaitAll(handles);

    Assert.Equal(true, success);
}

If you're testing UI functionality, you may be better using Calabash or a related framework that is dedicated to testing UI flow.

查看更多
登录 后发表回答