如何处理xUnit .net的Assert.Throws 中的Tasks抛出的exception?

以下异步xUnit.net测试使用标记有async修饰符的lambda失败,因为报告没有抛出exception:

  [Theory, AutoWebData] public async Task SearchWithNullQueryThrows( SearchService sut, CancellationToken dummyToken) { // Fixture setup // Exercise system and verify outcome Assert.Throws(async () => await sut.SearchAsync(null, dummyToken)); // Teardown } 

为了确保实际抛出ArgumentNullException我明确地使用了try-catch块。 它工作,但结果代码不干净(与第一次测试相比):

 [Theory, AutoWebData] public async Task SearchWithNullQueryThrows( SearchService sut, CancellationToken dummyToken) { // Fixture setup var expected = typeof(ArgumentNullException); Type actual = null; // Exercise system try { await sut.SearchAsync(null, dummyToken); } catch (ArgumentNullException e) { actual = e.GetType(); } // Verify outcome Assert.Equal(expected, actual); // Teardown } 

为什么带有用async修饰符标记的lambdaAssert.Throws失败?

更新

这已在xUnit 2中解决,添加了Assert.ThrowsAsync


我怀疑Assert.Throws不是async Assert.Throws 。 我建议使用xUnit团队提出此问题,建议添加ThrowsAsync

在这种情况下, async委托是返回TaskTask ,并且ArgumentNullException不会直接从委托中抛出; 相反,它被放置在TaskTask.Exception.InnerException )上。 Assert.Throws期望exception直接从委托中抛出,而不是放在返回值的属性上。

您可以创建自己的AssertEx.ThrowsAsync

 public static async Task ThrowsAsync(Func func) { var expected = typeof(TException); Type actual = null; try { await func(); } catch (Exception e) { actual = e.GetType(); } Assert.Equal(expected, actual); } 

可以这样使用:

 [Theory, AutoWebData] public async Task SearchWithNullQueryThrows( SearchService sut, CancellationToken dummyToken) { // Fixture setup // Exercise system and verify outcome await AssertEx.ThrowsAsync(async () => await sut.SearchAsync(null, dummyToken)); // Teardown } 

我在MSTest中使用了类似的方法。

如果您还需要返回exception以进行validation,那么这可能很有用:

 public static async Task AssertThrowsAsync(Func func) { var expected = typeof (TException); Exception exception = null; Type actual = null; try { await func(); } catch (Exception e) { actual = e.GetType(); exception = e; } Assert.NotNull(exception); Assert.Equal(expected, actual); return exception; }