Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing FindAsync

I've set up a test project using the async query provider found in this excellent MSDN article: http://msdn.microsoft.com/en-US/data/dn314429#async which works great.

However when I add a method which calls FindAsync:

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

And add the following unit test in the format:

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

However when GetBlog is called from my test method, await _context.Blogs.FindAsync(blogId); throws a NullReferenceException at TestingDemo.BlogService.<GetBlog>d__5.MoveNext()

Any suggestions how I can implement unit tests on methods calling FindAsync using the testing methodology found in the MSDN article: http://msdn.microsoft.com/en-US/data/dn314429#async ?

like image 258
Andy Avatar asked Dec 04 '13 17:12

Andy


1 Answers

NullReferenceException inside a MoveNext for an async method is almost always due to returning null from another async method.

In this case, it looks like FindAsync is returning null, which makes sense since I don't see where you're mocking it. You're currently mocking the IQueryable and GetAsyncEnumerator aspects, but not FindAsync. The example article you posted does not provide a complete DbSet mocking solution.

like image 81
Stephen Cleary Avatar answered Sep 24 '22 12:09

Stephen Cleary