单元测试FindAsync

本文关键字:FindAsync 单元测试 | 更新日期: 2024-07-10 19:14:02

我已经使用这篇优秀的MSDN文章中的异步查询提供程序建立了一个测试项目:http://msdn.microsoft.com/en-US/data/dn314429#async这非常有效。

但是,当我添加一个调用FindAsync:的方法时

public async Task<Blog> GetBlog(int blogId)
{
    return await _context.Blogs.FindAsync(blogId);
}

并在格式中添加以下单元测试:

[TestMethod]
public async Task GetAllBlogsAsync_gets_blog()
{
    var data = new List<Blog>
    {
        new Blog { BlogId = 1, Name = "BBB" },
        new Blog { BlogId = 2, Name = "ZZZ" },
        new Blog { BlogId = 3, Name = "AAA" },
    }.AsQueryable();
    var mockSet = new Mock<DbSet<Blog>>();
    mockSet.As<IDbAsyncEnumerable<Blog>>()
        .Setup(m => m.GetAsyncEnumerator())
        .Returns(new TestDbAsyncEnumerator<Blog>(data.GetEnumerator()));
    mockSet.As<IQueryable<Blog>>()
        .Setup(m => m.Provider)
        .Returns(new TestDbAsyncQueryProvider<Blog>(data.Provider));
    mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType);
    mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
    var mockContext = new Mock<BloggingContext>();
    mockContext.Setup(c => c.Blogs).Returns(mockSet.Object);
    var service = new BlogService(mockContext.Object);
    var blog = await service.GetBlog(2);
    Assert.AreEqual("ZZZ", blog.Name);
}

但是,当从我的测试方法调用GetBlog时,await _context.Blogs.FindAsync(blogId);抛出一个NullReferenceExceptionTestingDemo.BlogService.<GetBlog>d__5.MoveNext()

关于如何使用MSDN文章中的测试方法在调用FindAsync的方法上实现单元测试的任何建议:http://msdn.microsoft.com/en-US/data/dn314429#async?

单元测试FindAsync

对于async方法,MoveNext中的NullReferenceException几乎总是由于从另一个异步方法返回null

在这种情况下,看起来FindAsync正在返回null,这是有道理的,因为我看不出你在哪里嘲笑它。你目前正在嘲笑IQueryableGetAsyncEnumerator方面,但没有嘲笑FindAsync。您发布的示例文章没有提供完整的DbSet模拟解决方案。

我也遇到过这个问题。还有另一种解决方案,它既快速又简单,尤其是当您只期望一个结果,并且不需要依赖于上下文缓存时。即使用SingleOrDefaultAsync而不是FindAsync。

旧版本:

public async Task<Blog> GetBlog(int blogId)
{
    return await _context.Blogs.FindAsync(blogId);
}

新版本:

public async Task<Blog> GetBlog(int blogId)
{
    return await _context.Blogs.Where(b => b.BlogId == blogId).SingleOrDefaultAsync();
}

这个版本将使用您所拥有的嘲讽代码。

(这篇文章的答案解释了区别:Include与async await的使用)