我们正在使用 MSTest 和 Moq 为异步代码编写单元测试。
所以我们有一些看起来像这样的代码:
var moq = new Mock<Foo>();
moq.Setup(m => m.GetAsync())
.Returns(Task.FromResult(10));
或者像这样在具有更新版本 Moq 的项目上
var moq = new Mock<Foo>();
moq.Setup(m => m.GetAsync())
.ReturnsAsync(10);
查看 ReturnsAsync 的 Moq 实现:
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);
}
这两种方法在引擎盖下似乎是相同的。两者都创建一个TaskCompletionSource
,调用SetResult
并返回Task
到目前为止,一切都很好。
但是短期运行的async
方法被优化为同步运行。这似乎意味着TaskCompletionSource
始终是同步的,这似乎也表明上下文处理和任何可能发生的相关问题永远不会发生。
因此,如果我们有一些代码执行了一些async
禁止操作,例如混合和awaits
,那么在单元测试中就不会检测到这些问题。Wait()
Result
创建一个总是产生控制权的扩展方法有什么好处吗?就像是 :
public async Task<T> ReturnsYieldingAsync<T>(T result)
{
await Task.Yield();
return result;
}
在这种情况下,我们将有一个保证异步执行的方法。
感知到的优势将是检测错误的异步代码。例如,它可以在单元测试期间捕获任何死锁或异常吞咽。
我不是 100% 肯定是这种情况,所以我真的很想听听社区的意见。