简体   繁体   English

Xamarin中的NUnit异步测试不起作用

[英]NUnit Async Testing in Xamarin Not Working

I'm new to the C# world, trying to give Xamarin an evaluation. 我是C#世界的新手,试图给Xamarin一个评价。 I've been making a small web api library, and it has been going smoothly so far, but now that I'm trying to test networking components, I'm having some trouble. 我一直在制作一个小型的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

The class / method: 类/方法:

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

The NUnit test class / case: 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 );
        }
    }
}

All of my other tests seem to be working (parsing, etc), but this one just goes right by, acting as if it passed, but I don't see how it could have, with the contradictory assertions. 我的所有其他测试似乎都在工作(解析等),但是这个测试恰好是正确的,就好像它已经过去一样,但是我看不出它是如何产生的,带有矛盾的断言。

Is this not supported currently, or am I incorrect in my implementation? 目前不支持,还是我的实施不正确?

If I make it synchronous with ContinueWith() / Wait() , it works as expected, but obviously I don't want to have duplicate implementations in my library, just to pass the tests. 如果我使它与ContinueWith() / Wait()同步,它按预期工作,但显然我不想在我的库中有重复的实现,只是为了通过测试。

NUnit does support async Task unit tests; NUnit支持async Task单元测试; unfortunately, Xamarin is using an older version of NUnit that does not. 不幸的是,Xamarin使用的是较旧版本的NUnit。 However, I do not recommend synchronously blocking on the task directly because that will complicate your error path testing (exceptions are wrapped in an AggregateException ). 但是,我不建议直接同步阻塞任务,因为这会使错误路径测试变得复杂(异常包含在AggregateException )。

I have an AsyncContext type in my AsyncEx library that can be used as such: 我的AsyncEx库中有一个AsyncContext类型,可以这样使用:

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

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

You have an async void method. 你有一个async void方法。 This should be a big red flag whenever you use it. 无论何时使用它都应该是一个大红旗。

As soon as TempTest hits the very first await it will return to the caller. 一旦TempTest点击第一个await它将返回到调用者。 The rest of the code runs , but from the point of view of the caller the method has completed, and the caller has no way of knowing when the method ends, any exceptions it throws, any asserts that fail, etc. 其余的代码运行 ,但从调用者的角度来看,方法已经完成,并且调用者无法知道方法何时结束,它抛出的任何异常,任何失败的断言等。

When you're synchronously waiting you are of course ensuring that the exception is thrown by the thread that calls this method, rather than in some other thread in some other place where the testing framework can't observe it. 当您同步等待时,您当然要确保调用此方法的线程抛出异常,而不是在测试框架无法观察到的其他位置的某个其他线程中抛出异常。

To properly test an asynchronous method the testing framework really needs to have been designed to support it, really. 为了正确测试异步方法,测试框架确实需要设计为支持它,真的。 It should be able to handle methods that return a Task , and act based on the results of that Task . 它应该能够处理返回Task方法,并根据该Task的结果进行操作。 If that's not an option, you'll need to do this work manually. 如果这不是一个选项,您需要手动完成这项工作。 Ideally, to maintain proper asynchrony, instead of waiting on any of the tasks, you should set up your own message pump (see here for an example) which will be able to pump the messages until the top level operation finishes, thus allowing you to run asynchronous code in a synchronous method. 理想情况下,要保持正确的异步,而不是等待任何任务,您应该设置自己的消息泵(请参阅此处的示例),它将能够提取消息,直到顶级操作完成,从而允许您在同步方法中运行异步代码。

The sequence of operations here is: 这里的操作顺序是:

  1. NUnit runs TempTest() NUnit运行TempTest()
  2. TempTest calls new AsyncTest().DoTest(), which returns a Task TempTest调用新的AsyncTest()。DoTest(),它返回一个Task
  3. The rest of TempTest (the asserts) is scheduled as a continuation on the task 其余的TempTest(断言)被安排为任务的延续
  4. The TempTest method returns (void), and NUnit moves onto the next test TempTest方法返回(void),NUnit移动到下一个测试
  5. The continuation executes the asserts at some point in the future 延续在将来的某个时刻执行断言
  6. Since nothing is observing the continuation, the assert failure exception is unhandled 由于没有任何东西正在观察延续,因此断言失败异常未得到处理

What you probably want is for your test to be synchronous, and block on the result of the asynchronous thing you're testing: 您可能想要的是让您的测试同步,并阻止您正在测试的异步事物的结果:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM