Mocking Methods of Asynchronous Programming

We write unit tests for asynchronous code using MSTest and Moq.

So, we have some code that looks something like this:

var moq = new Mock<Foo>(); moq.Setup(m => m.GetAsync()) .Returns(Task.FromResult(10)); 

Or as in projects with a later version of Moq

 var moq = new Mock<Foo>(); moq.Setup(m => m.GetAsync()) .ReturnsAsync(10); 

Looking at the implementation of Moq ReturnsAsync:

 public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, Task<TResult>> mock, TResult value) where TMock : class { TaskCompletionSource<TResult> completionSource = new TaskCompletionSource<TResult>(); completionSource.SetResult(value); return mock.Returns(completionSource.Task); } 

Both methods seem the same under the hood. Both create a TaskCompletionSource , call SetResult and return a Task

So far so good.

But async short methods are optimized for synchronous action. This seems to mean that the TaskCompletionSource always synchronous, which would also indicate that context processing and any problems associated with this might not happen.

So, if we had some code that executed some async no-no's, such as mixing awaits , Wait() and Result , that these problems would not be detected during unit testing.

Was there any advantage in creating an extension method that always gives you control? Sort of:

 public async Task<T> ReturnsYieldingAsync<T>(T result) { await Task.Yield(); return result; } 

In this case, we will have a method that is guaranteed to execute asynchronously.

The perceived advantage would be to detect bad asynchronous code. For example, it can catch any deadlock or exception when swallowing during unit testing.

I'm not 100% sure, it is, so I would be interested to know what the community has to say.

+5
source share
1 answer

When I first started talking about asynchronous testing four years ago (!), I would recommend developers to test along the async axis for their mocks. That is, the test along the axis of the result (success, failure), as well as the asynchronous axis (sync, async).

However, over time, I eased it. When it comes to testing my own code, I really only check the synchronous success / failure paths, unless there is a clear reason to also check the asynchronous success path for this code. I no longer worry about asynchronous failure testing.
+2
source

Source: https://habr.com/ru/post/1240590/


All Articles