针对特定exception的unit testing异步方法

有没有人有一个如何在Windows 8 Metro应用程序中unit testing异步方法的示例,以确保它抛出所需的exception?

给定一个具有异步方法的类

public static class AsyncMathsStatic { private const int DELAY = 500; public static async Task Divide(int A, int B) { await Task.Delay(DELAY); if (B == 0) throw new DivideByZeroException(); else return A / B; } } 

我想使用新的Async.ExpectsException构造编写测试方法。 我试过了 :-

 [TestMethod] public void DivideTest1() { Assert.ThrowsException(async () => { int Result = await AsyncMathsStatic.Divide(4, 0); }); } 

但是当然测试不等待异步方法完成,因此导致测试失败,但没有抛出exception。

您可以使用与常规ExpectedExceptionAttributeasync Taskunit testing:

 [TestMethod] [ExpectedException(typeof(DivideByZeroException))] public async Task DivideTest1() { int Result = await AsyncMathsStatic.Divide(4, 0); } 

从评论更新: Win8unit testing项目中的ExpectedExceptionAttribute 已替换为Assert.ThrowsException ,这是一个很好的未记录的AFAICT。 这在设计方面是一个很好的改变 ,但我不知道为什么它只在Win8上得到支持。

好吧,假设没有async兼容的Assert.ThrowsException (由于缺少文档而无法判断是否存在),您可以自己构建一个:

 public static class AssertEx { public async Task ThrowsExceptionAsync(Func code) { try { await code(); } catch (Exception ex) { if (ex.GetType() == typeof(TException)) return; throw new AssertFailedException("Incorrect type; expected ... got ...", ex); } throw new AssertFailedException("Did not see expected exception ..."); } } 

然后使用它:

 [TestMethod] public async Task DivideTest1() { await AssertEx.ThrowsException(async () => { int Result = await AsyncMathsStatic.Divide(4, 0); }); } 

请注意,我的示例只是对exception类型进行精确检查; 您可能也希望允许后代类型。

更新2012-11-29:打开UserVoice建议 ,将其添加到Visual Studio。

 [TestMethod] public void DivideTest1() { Func action = async () => { int Result = await AsyncMathsStatic.Divide(4, 0); }); action.ShouldThrow(); } 

使用.ShouldThrow() nuget包适合我

几天前我遇到了类似的问题,并最终创造了类似于斯蒂芬上面的回答。 它可以作为一个要点 。 希望它有所帮助 – github要点有完整的代码和示例用法。

 ///  /// Async Asserts use with Microsoft.VisualStudio.TestPlatform.UnitTestFramework ///  public static class AsyncAsserts { ///  /// Verifies that an exception of type  is thrown when async is executed. /// The assertion fails if no exception is thrown ///  /// The generic exception which is expected to be thrown /// The async Func which is expected to throw an exception /// The task object representing the asynchronous operation. public static async Task ThrowsException(Func func) where T : Exception { return await ThrowsException(func, null); } ///  /// Verifies that an exception of type  is thrown when async is executed. /// The assertion fails if no exception is thrown ///  /// The generic exception which is expected to be thrown /// The async Func which is expected to throw an exception /// A message to display if the assertion fails. This message can be seen in the unit test results. /// The task object representing the asynchronous operation. public static async Task ThrowsException(Func func, string message) where T : Exception { if (func == null) { throw new ArgumentNullException("func"); } string failureMessage; try { await func(); } catch (Exception exception) { if (!typeof(T).Equals(exception.GetType())) { // "Threw exception {2}, but exception {1} was expected. {0}\nException Message: {3}\nStack Trace: {4}" failureMessage = string.Format( CultureInfo.CurrentCulture, FrameworkMessages.WrongExceptionThrown, message ?? string.Empty, typeof(T), exception.GetType().Name, exception.Message, exception.StackTrace); Fail(failureMessage); } else { return (T)exception; } } // "No exception thrown. {1} exception was expected. {0}" failureMessage = string.Format( CultureInfo.CurrentCulture, FrameworkMessages.NoExceptionThrown, message ?? string.Empty, typeof(T)); Fail(failureMessage); return default(T); } private static void Fail(string message, [CallerMemberName] string assertionName = null) { string failureMessage = string.Format( CultureInfo.CurrentCulture, FrameworkMessages.AssertionFailed, assertionName, message); throw new AssertFailedException(failureMessage); } } 

自Visual Studio 2012 Update 2中添加了对在 ThrowsException方法中使用异步lambdas的支持,但仅适用于Windowsapp store测试项目。

一个问题是你需要使用Microsoft.VisualStudio.TestPlatform.UnitTestFramework.AppContainer.Assert类来调用ThrowsException

因此,要使用新的ThrowsException方法,您可以执行以下操作:

 using AsyncAssert = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.AppContainer.Assert; [TestMethod] public void DivideTest1() { AsyncAssert.ThrowsException(async () => { int Result = await AsyncMathsStatic.Divide(4, 0); }); }