我是async / await世界的新手,我试图找出为异步方法编写异步单元测试的好处。也就是说,异步方法的单元测试是否必须异步调用异步方法?如果它使用Task.Run()同步调用异步方法,会丢失什么?在后一种情况下,代码覆盖范围并没有受到影响。
我之所以这么说是因为我们的模拟软件(我们使用TypeMock)不能支持async / await。 (They say there is a legitimate reason因为缺乏支持,我不同意它们。)通过在单元测试中同步调用异步方法,我们可以解决这个问题。但是,我想通过这样做来了解我们是否正在削减任何角落。
例如,假设我有以下异步方法:
public async Task<string> GetContentAsync(string source)
{
string result = "";
// perform magical async IO bound work here to populate result
return result;
}
以下是不起作用的理想单元测试:
[TestMethod()]
public async Task GetContentAsyncTest()
{
string expected = "thisworks";
var worker = new Worker();
// ...mocking code here that doesn't work!
string actual = await worker.GetContentAsync();
Assert.AreEqual(expected, actual);
}
但这很有效,它确实提供了我们需要的代码覆盖率。这样好吗?
[TestMethod()]
public void GetContentAsyncTest()
{
string expected = "thisworks";
var worker = new Worker();
// mocking code here that works!
string actual = Task.Run(() => worker.GetContentAsync()).Result;
Assert.AreEqual(expected, actual);
}
答案 0 :(得分:3)
异步方法的单元测试是否必须异步调用async方法?
不,但这样做是最自然的。
如果它使用Task.Run()同步调用异步方法,会丢失什么?
没什么。它的表现稍差,但在某种程度上你可能永远不会注意到。
您可能希望使用GetAwaiter().GetResult()
代替Result
来避免失败测试中的AggregateException
包装。你也可以直接调用这个方法;无需将其包装在Task.Run
。
他们说这种缺乏支持是有正当理由的,我并不反对他们。
哦,我当然不同意他们的看法。 :)
这是否意味着他们无法对迭代器块进行单元测试?完全相同的推理将适用......
不支持async
单元测试的唯一更严重的问题是,测试中的代码假设其上下文将处理同步。这种情况很常见,例如,在中等复杂的View模型中。
在这种情况下,您需要安装一个上下文来执行async
代码(例如,我的AsyncContext
type),除非您使用单元测试框架自动提供一个(截至本文撰写时,只有xUnit执行AFAIK)。
答案 1 :(得分:2)
如果您使用xUnit而不是MSTest,您的理想解决方案(异步测试)将起作用。