In this article, we are going to learn how to mock asynchronous methods using Moq.
Moq is an easy-to-use and most popular framework to mock tests using .NET.
Let’s start it.
The Repository Project We Are Going to Test
This project MockAsynchrounousMethods.Repository
represents a Repository Pattern that connects our source code with a fake database.
Since the repository creation is not this article’s main goal, we are not going to show all the classes and interfaces, but the main class that we are going to test. That said, let’s inspect the ArticleRepository
class:
public class ArticleRepository : IArticleRepository { private readonly IFakeDbArticles _fakeDbArticle; public ArticleRepository(IFakeDbArticles fakeDbArticle) { _fakeDbArticle = fakeDbArticle; } public async Task<ArticleDbModel?> GetArticleAsync(int id) { return await _fakeDbArticle.GetByIdAsync(id); } public async Task<IEnumerable<ArticleDbModel>> GetAllArticlesAsync() { return await _fakeDbArticle.GetAsync(); } }
This class implements the IArticleRepository
interface. Note that all these methods are asynchronous, and they simply retrieve data from the FakeDbArticles
class:
public class FakeDbArticles : List<ArticleDbModel>, IFakeDbArticles { private readonly static List<ArticleDbModel> _articles = Populate(); private static List<ArticleDbModel> Populate() { var result = new List<ArticleDbModel>() { new ArticleDbModel { Id = 1, Title = "First Article", LastUpdate = DateTime.Now }, ... }; return result; } public async Task<IEnumerable<ArticleDbModel>> GetAsync() { return await Task.FromResult(_articles); } public async Task<ArticleDbModel?> GetByIdAsync(int id) { return await Task.FromResult(_articles.FirstOrDefault(x => x.Id == id)); } }
For further details, you can check the full implementation of this Repository in this article’s source code.
XUnit Test Project to Mock Asynchoronus Methods
Now that the repository is ready, let’s create MockAsynchronousMethods.Tests
XUnit Test Project.
Once the project is ready, let’s add the MockAsynchronousMethods.Repository
as a reference by right-clicking in the dependencies and then Add Project Reference
.
For the next step, we need to install the Moq Framework:
Install-Package Moq
Once it is done, let’s create a Mock folder, and, inside it, aFakeDbArticleMock
class that inherits from Mock<IFakeDbArticles>
.
public class FakeDbArticleMock : Mock<IFakeDbArticles> { }
And a FakeDb class to hold a list with some articles:
public static class FakeDb { public static List<ArticleDbModel> Articles = new List<ArticleDbModel>() { new ArticleDbModel { Id = 1, Title = "First Article", LastUpdate = DateTime.Now }, new ArticleDbModel { Id = 2, Title = "Second title", LastUpdate = DateTime.Now }, new ArticleDbModel { Id = 3, Title = "Third title", LastUpdate = DateTime.Now } }; }
Now, let’s start the setup of our mocks:
public FakeDbArticleMock GetByIdAsync() { Setup(x => x.GetByIdAsync(It.IsAny<int>())) .ReturnsAsync(FakeDb.Articles.First()); return this; }
In this method, we set up an asynchronous mock call to the GetByIdAsync
method from the IFakeDbArticle
interface. This method returns the first article from the list we created inside the FakeDb
class.
When we mock an asynchronous method, instead of using a standard Return(...)
method, we use the ReturnAsync(...)
method, which makes our mock asynchronous.
It is good to mention that, the ReturnAsync
was introduced in version 4.5.28. In the previous versions of the Moq Framework, it was a bit different:
Setup(x => x.GetByIdAsync(It.IsAny<int>())) .Returns(Task.FromResult<ArticleDbModel?>(articleDbModel));
You can check the other mock methods in the full FakeDbArticleMock class implementation here.
Now that all mocks are ready, it is time to test our code.
At the root of the test project, let’s create an ArticleRepositoryTest
class, responsible for holding every test method of this article.
And then, let’s create a test method:
[Fact] public async Task GivenAMockedDatabase_WhenRequestingAnExistingArticleAsynchronously_ThenReturnASingleArticle() { var mockArticleRepository = new FakeDbArticleMock() .GetByIdAsync(); var articleRepository = new ArticleRepository(mockArticleRepository.Object); var result = await articleRepository.GetArticleAsync(1); Assert.NotNull(result); Assert.Equal(FakeDb.Articles.First(), result); }
First, we instantiate the FakeDbArticleMock
class and indicate which setup we want to use for this test. Then, it is necessary to instantiate the repository we want to test and inject the mock instance into it.
Finally, we call the method we are testing and assert the results.
You can check the other test methods in our source code.
Conclusion
In this article, we’ve learned how to mock asynchronous methods using the Moq framework. We’ve also seen that Moq Framework introduced the ReturnsAsync
method in version 4.2.28+, and learned how to test asynchronous methods with older versions.