为什么在不使用async / await关键字时异步unit testing失败?
根据这个讨论 ,以下两种方法应该没有区别:
public async Task Foo() { await DoSomethingAsync(); } public Task Foo() { return DoSomethingAsync(); }
实际上,似乎对于非常简单的方法, 没有 async / await关键字的调用将是首选,因为它们会消除一些开销。
然而,这显然并不总是在unit testing中起作用。
MSTest的
[TestClass] public class AsyncTest { [TestMethod] public async Task Test1() { await Task.Delay(0); } [TestMethod] public Task Test2() { return Task.Delay(0); } }
NUnit的
[TestFixture] public class AsyncTest { [Test] public async Task Test1() { await Task.Delay(0); } [Test] public Task Test2() { return Task.Delay(0); } }
的xUnit
public class AsyncTest { [Fact] public async Task Test1() { await Task.Delay(0); } [Fact] public Task Test2() { return Task.Delay(0); } }
- 在所有情况下,
Test1
通过了。 - 在MSTest中,
Test2
出现在测试运行器中,但它没有运行。 -
在NUnit中,将忽略
Test2
,并显示以下消息:测试方法具有非void返回类型,但不期望结果
-
在XUnit中,
Test2
通过。
由于任务仍在等待所有情况,因此影响NUnit和MSTest测试运行器的async
关键字是什么? 或许有些反思问题?
听起来那些测试运行器可能正在使用reflection来检查返回Task
的方法是否真的是异步方法。 这并不意味着如果它们被运行,该方法会表现得不同 – 但它们只是没有被运行。
这就像说:
public string Name { get; set; }
相当于:
private string name; public Name { get { return name; } set { name = value; } }
它们在行为方面在逻辑上是相同的,但如果你用reflection努力,你可以分辨出来。 在这种特殊情况下,还有其他更微妙的差异,但同样的一般原则适用。
它看起来像在当前的NUnit代码中(在撰写本文时),检测是在AsyncInvocationRegion.cs
。
不可否认,编写unit testing返回Task
但不使用异步方法至少是不寻常的 – 但这绝非不可能。