单元测试异步方法-测试永远不会完成 [英] Unit testing async method - test never completes

查看:94
本文介绍了单元测试异步方法-测试永远不会完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对正在构建的类进行单元测试,该类将调用许多URL(异步)并检索其内容.

I'm trying to unit test my a class I'm building that calls a number of URLs (Async) and retrieves the contents.

这是我遇到问题的测试:

Here's the test I'm having a problem with:

[Test]
public void downloads_content_for_each_url()
{
    _mockGetContentUrls.Setup(x => x.GetAll())
        .Returns(new[] { "http://www.url1.com", "http://www.url2.com" });

    _mockDownloadContent.Setup(x => x.DownloadContentFromUrlAsync(It.IsAny<string>()))
        .Returns(new Task<IEnumerable<MobileContent>>(() => new List<MobileContent>()));

    var downloadAndStoreContent= new DownloadAndStoreContent(
        _mockGetContentUrls.Object, _mockDownloadContent.Object);

    downloadAndStoreContent.DownloadAndStore();

    _mockDownloadContent.Verify(x => x.DownloadContentFromUrlAsync("http://www.url1.com"));
    _mockDownloadContent.Verify(x => x.DownloadContentFromUrlAsync("http://www.url2.com"));
}

DownloadContent 的相关部分是:

    public void DownloadAndStore()
    {
        //service passed in through ctor
        var urls = _getContentUrls.GetAll();

        var content = DownloadAll(urls)
            .Result;

        //do stuff with content here
    }

    private async Task<IEnumerable<MobileContent>> DownloadAll(IEnumerable<string> urls)
    {
        var list = new List<MobileContent>();

        foreach (var url in urls)
        {
            var content = await _downloadMobileContent.DownloadContentFromUrlAsync(url);
            list.AddRange(content);
        }

        return list;
    }

运行测试时,它永远不会完成-只是挂起.

When my test runs, it never completes - it just hangs.

我怀疑应该怪我的 _mockDownloadContent 设置中的某件事...

I suspect something in the setup of my _mockDownloadContent is to blame...

推荐答案

您的问题出在此模拟游戏中:

Your problem is in this mock:

new Task<IEnumerable<MobileContent>>(() => new List<MobileContent>())

您不应在异步代码中使用 Task 构造函数.而是使用 Task.FromResult :

You should not use the Task constructor in asynchronous code. Instead, use Task.FromResult:

Task.FromResult<IEnumerable<MobileContent>>(new List<MobileContent>())

我建议您阅读我的 MSDN文章

I recommend you read my MSDN article or async blog post which point out that the Task constructor should not be used for async code.

此外,我建议您采纳Servy的建议并一直"进行异步(这在我的MSDN文章中也已有介绍).如果您正确使用 await ,则您的代码将更改为如下所示:

Also, I recommend you do take Servy's advice and do async "all the way" (this is also covered by my MSDN article). If you use await properly, your code would change to look like this:

public async Task DownloadAndStoreAsync()
{
    //service passed in through ctor
    var urls = _getContentUrls.GetAll();
    var content = await DownloadAllAsync(urls);
    //do stuff with content here
}

您的测试如下:

[Test]
public async Task downloads_content_for_each_url()
{
  _mockGetContentUrls.Setup(x => x.GetAll())
    .Returns(new[] { "http://www.url1.com", "http://www.url2.com" });

  _mockDownloadContent.Setup(x => x.DownloadContentFromUrlAsync(It.IsAny<string>()))
    .Returns(Task.FromResult<IEnumerable<MobileContent>>(new List<MobileContent>()));

  var downloadAndStoreContent= new DownloadAndStoreContent(
    _mockGetContentUrls.Object, _mockDownloadContent.Object);

  await downloadAndStoreContent.DownloadAndStoreAsync();

  _mockDownloadContent.Verify(x => x.DownloadContentFromUrlAsync("http://www.url1.com"));
  _mockDownloadContent.Verify(x => x.DownloadContentFromUrlAsync("http://www.url2.com"));
}

请注意,现代版本的NUnit可以理解 async Task 单元测试,而不会出现任何问题.

Note that modern versions of NUnit understand async Task unit tests without any problems.

这篇关于单元测试异步方法-测试永远不会完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆