【问题标题】:NUnit Async Testing in Xamarin Not WorkingXamarin 中的 NUnit 异步测试不起作用
【发布时间】:2014-01-20 12:12:02
【问题描述】:

我是 C# 世界的新手,正在尝试对 Xamarin 进行评估。我一直在做一个小型的web api库,到目前为止进展顺利,但是现在我正在尝试测试网络组件,我遇到了一些麻烦。

OS:           OS X 10.9.1
Xamarin:      4.2.2 (build 2)
Library:      PCL targeting 4.0 (Profile158)
Nunit target: Mono / .NET 4.5

类/方法:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http;

namespace LibTest
{
    public class AsyncTest
    {
        public async Task<string> DoTest()
        {
            return await new HttpClient().GetStringAsync( "http://www.reddit.com/.json?limit=1" );
        }
    }
}

NUnit 测试类/案例:

using System;
using NUnit.Framework;
using LibTest;

namespace LibTestTests
{
    [TestFixture]
    public class LibTestTest
    {
        [Test]
        public async void TempTest()
        {
            string data = await new AsyncTest().DoTest();

            Assert.IsNotNull( data );
            Assert.IsNull( data );
        }
    }
}

我的所有其他测试似乎都在工作(解析等),但这个测试只是通过了,就好像它通过了一样,但我不明白它是如何发生的,而且断言相互矛盾。

目前不支持此功能,还是我的实现不正确?

如果我使它与ContinueWith() / Wait() 同步,它会按预期工作,但显然我不想在我的库中重复实现,只是为了通过测试。

【问题讨论】:

    标签: c# mono nunit xamarin async-await


    【解决方案1】:

    NUnit 确实支持async Task 单元测试;不幸的是,Xamarin 使用的不是旧版本的 NUnit。但是,我不建议直接同步阻塞任务,因为这会使您的错误路径测试变得复杂(异常包含在 AggregateException 中)。

    我的AsyncEx library 中有一个AsyncContext 类型,可以这样使用:

    [Test]
    public void TempTest()
    {
        AsyncContext.Run(async () =>
        {
            string data = await new AsyncTest().DoTest();
    
            Assert.IsNotNull( data );
            Assert.IsNull( data );
        });
    }
    

    【讨论】:

    • 太棒了,我同意阻塞不太理想,以后我在电脑上时肯定会检查那个库。
    • 所以,我只能在使用异步 lambda 时编译和运行它,async () =&gt; {},但随后我得到:Could not load type 'System.Object' from assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. I used Nuget to install Nitro.AsyncEx, version 2.1.3`。
    • 会不会是因为Nunit项目的目标框架是Mono / .NET 4.5
    • 对不起;对于 iOS 项目,您必须确保包含并编译了引用的 dll。我在这里没有很多经验,但是this question may help
    【解决方案2】:

    你有一个async void 方法。每当您使用它时,这应该是一个很大的危险信号。

    一旦TempTest 击中第一个await,它将返回给调用者。其余代码运行,但从调用者的角度来看,方法已经完成,调用者无法知道方法何时结束、它抛出的任何异常、任何失败的断言等。

    当您同步等待时,您当然要确保异常是由调用此方法的线程引发的,而不是在测试框架无法观察到的其他地方的其他线程中引发的。

    要正确测试异步方法,测试框架确实需要设计为支持它,真的。它应该能够处理返回Task 的方法,并根据Task 的结果采取行动。如果这不是一个选项,您将需要手动完成这项工作。理想情况下,为了保持适当的异步性,而不是等待任何任务,您应该设置自己的消息泵(参见here 示例),它将能够泵送消息直到顶级操作完成,从而允许您可以在同步方法中运行异步代码。

    【讨论】:

    • 谢谢,这很有道理。
    【解决方案3】:

    这里的操作顺序是:

    1. NUnit 运行 TempTest()
    2. TempTest 调用 new AsyncTest().DoTest(),它返回一个 Task
    3. TempTest 的其余部分(断言)被安排为任务的延续
    4. TempTest 方法返回 (void),NUnit 进入下一个测试
    5. continuation 在未来某个时间点执行断言
    6. 由于没有观察到延续,断言失败异常未处理

    您可能希望您的测试是同步的,并阻止您正在测试的异步事物的结果:

    [Test]
    public void TempTest()
    {
        string data = new AsyncTest().DoTest().Result;
    
        Assert.IsNotNull( data );
        Assert.IsNull( data );
    }
    

    【讨论】:

    • 啊,这很有道理。虽然它并不理想,但我认为等待是保持库异步性的最佳选择。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多