有没有人举例说明如何在Windows 8 Metro应用程序中对异步方法进行单元测试,以确保它抛出所需的异常?
给定一个带有异步方法的类
public static class AsyncMathsStatic
{
private const int DELAY = 500;
public static async Task<int> 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<DivideByZeroException>(async () => { int Result = await AsyncMathsStatic.Divide(4, 0); });
}
但当然测试不会等待异步方法完成,因此导致测试失败,但是没有抛出异常。
答案 0 :(得分:16)
您可以对常规ExpectedExceptionAttribute
使用async Task
单元测试:
[TestMethod]
[ExpectedException(typeof(DivideByZeroException))]
public async Task DivideTest1()
{
int Result = await AsyncMathsStatic.Divide(4, 0);
}
来自评论的更新 ExpectedExceptionAttribute
有关Assert.ThrowsException
的Win8单元测试项目has been replaced,这是很好的未记录的AFAICT。这是a good change design-wise,但我不知道为什么Win8上只支持 。
好吧,假设没有async
- 兼容Assert.ThrowsException
(由于缺少文档,我无法判断是否一个),你可以构建一个人自己:
public static class AssertEx
{
public async Task ThrowsExceptionAsync<TException>(Func<Task> 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<DivideByZeroException>(async () => {
int Result = await AsyncMathsStatic.Divide(4, 0);
});
}
请注意,我的示例只是对异常类型进行精确检查;您可能也希望允许后代类型。
更新2012-11-29:打开UserVoice suggestion将其添加到Visual Studio。
答案 1 :(得分:3)
[TestMethod]
public void DivideTest1()
{
Func<Task> action = async () => { int Result = await AsyncMathsStatic.Divide(4, 0); });
action.ShouldThrow<DivideByZeroException>();
}
使用FluentAssertions中的.ShouldThrow()
nuget包适用于我
答案 2 :(得分:2)
通过添加ThrowsExceptionAsync
method,现在可以在本地覆盖此内容,而无需MSTest中的第三方或扩展方法:
await Assert.ThrowsExceptionAsync<Exception>(() => { Fail(); });
答案 3 :(得分:1)
几天前我遇到了类似的问题,结果创造了类似于斯蒂芬上面回答的问题。它以Gist的形式提供。希望它有所帮助 - github要点有完整的代码和样本用法。
/// <summary>
/// Async Asserts use with Microsoft.VisualStudio.TestPlatform.UnitTestFramework
/// </summary>
public static class AsyncAsserts
{
/// <summary>
/// Verifies that an exception of type <typeparamref name="T"/> is thrown when async<paramref name="func"/> is executed.
/// The assertion fails if no exception is thrown
/// </summary>
/// <typeparam name="T">The generic exception which is expected to be thrown</typeparam>
/// <param name="func">The async Func which is expected to throw an exception</param>
/// <returns>The task object representing the asynchronous operation.</returns>
public static async Task<T> ThrowsException<T>(Func<Task> func) where T : Exception
{
return await ThrowsException<T>(func, null);
}
/// <summary>
/// Verifies that an exception of type <typeparamref name="T"/> is thrown when async<paramref name="func"/> is executed.
/// The assertion fails if no exception is thrown
/// </summary>
/// <typeparam name="T">The generic exception which is expected to be thrown</typeparam>
/// <param name="func">The async Func which is expected to throw an exception</param>
/// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param>
/// <returns>The task object representing the asynchronous operation.</returns>
public static async Task<T> ThrowsException<T>(Func<Task> 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);
}
}
答案 4 :(得分:0)
支持在ThrowsException
方法中使用异步lambda已经been added in Visual Studio 2012 Update 2,但仅适用于Windows应用商店测试项目。
唯一的问题是,您需要使用Microsoft.VisualStudio.TestPlatform.UnitTestFramework.AppContainer.Assert
课程来调用ThrowsException
。
因此,要使用新的ThrowsException方法,您可以执行以下操作:
using AsyncAssert = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.AppContainer.Assert;
[TestMethod]
public void DivideTest1()
{
AsyncAssert.ThrowsException<DivideByZeroException>(async () => {
int Result = await AsyncMathsStatic.Divide(4, 0); });
}
答案 5 :(得分:0)
这对我有用
public async Task TestMachineAuthBadJson() {
// Arrange
// act
DocsException ex = await Assert.ThrowsExceptionAsync<DocsException>(() => MachineAuth.GetToken());
//assert
StringAssert.Contains(ex.Message, "DOCS-API error: ");
}
答案 6 :(得分:0)
这是一个老问题,但我现在偶然发现了这个问题,并决定对该问题提供更新的答案。
Xuint 现在支持使用 Assert.ThrowsAsync
方法进行异步异常测试。
答案 7 :(得分:-1)
好吧,或者只用.GetAwaiter().GetResult()
来包装异常:
Assert.ThrowsException<DivideByZeroException>(() => AsyncMathsStatic.Divide(4, 0).GetAwaiter().GetResult());