.net 如何在异步方法中测试异常
我正在使用VisualStudio11测试版 鉴于此代码:.net 如何在异步方法中测试异常,.net,async-ctp,visual-studio-2012,.net,Async Ctp,Visual Studio 2012,我正在使用VisualStudio11测试版 鉴于此代码: namespace KC.DataAccess.Global { /// <summary>Global methods for SQL access</summary> public static class SQL { public async static void ExecuteNonQuery(string ConnStr, string Query)
namespace KC.DataAccess.Global
{
/// <summary>Global methods for SQL access</summary>
public static class SQL
{
public async static void ExecuteNonQuery(string ConnStr, string Query)
{
if (string.IsNullOrEmpty(ConnStr)) throw new ArgumentNullException("ConnStr");
if (string.IsNullOrEmpty(Query)) throw new ArgumentNullException("Query");
SqlConnection conn = new SqlConnection(ConnStr);
SqlCommand cmd = PrepSqlConnection(ref conn, Query);
Exception exc = null;
for (int i = 0; i < 3; i++)
try { await Task.Run(() => cmd.ExecuteNonQuery()); break; }
catch (Exception ex) { Thread.Sleep(50); exc = ex; }
if (exc != null) throw new ApplicationException("Command failed after maximum attempts", exc);
conn.Close();
conn.Dispose();
}
}
}
在本例中,ExecuteOnQuery的验证部分显然抛出了一个异常,我在调试它时看到它抛出
我已将测试方法更改为异步,并将语法更改为wait Task.Run=>Target.ExecuteNonQuery,但没有任何效果
问题:
ExecuteOnQuery是否正在引发异常?
为什么ExecuteOnQueryFail1没有看到异常?
在不放弃方法的异步性质的情况下,如何修改测试方法或方法本身,以正确处理异常并通过测试用例?
由于您的方法返回void,因此无法将异常传播到调用代码。如果将返回类型更改为Task,现在可以观察异常,但必须显式执行
我认为修改调用代码的最好方法就是调用。如果任务中的代码引发异常,Wait将引发包含原始异常的AggregateException。由于方法返回void,因此异常无法传播到调用代码。如果将返回类型更改为Task,现在可以观察异常,但必须显式执行
我认为修改调用代码的最好方法就是调用。如果任务中的代码引发异常,Wait将引发包含原始异常的AggregateException。VS11 Beta对返回任务的测试方法具有一流的支持 因此,如果您将签名更改为:
public async static Task ExecuteNonQuery(string ConnStr, string Query)
然后您可以对其进行如下测试:
using Target = KC.DataAccess.Global.SQL;
[TestMethod]
[TestCategory("Unit")]
[ExpectedException(typeof(ArgumentNullException))]
public async Task ExecuteNonQueryFail1()
{
await Target.ExecuteNonQuery(null, "select 1");
}
我自己还没有机会尝试这种新的支持,但我已经读到这应该是可行的
注意:除非必须返回void(例如,对于事件处理程序),否则应该在异步方法中返回Task。任务是可等待的,因此代码更易于重用。我把这件事写进去
如果出于某种原因确实需要测试异步void方法,则需要提供自己的SynchronizationContext来捕获任何异常。请参阅的异步单元测试部分
我有几篇博客文章专门讨论异步单元测试。我为VS2010+AsyncCTP或VS11DevpReview编写了一个基本的异步单元测试项目,但我还没有机会用VS11Beta测试它。如果需要,这将是单元测试异步void方法的最简单方法 VS11 Beta对返回任务的测试方法具有一流的支持 因此,如果您将签名更改为:
public async static Task ExecuteNonQuery(string ConnStr, string Query)
然后您可以对其进行如下测试:
using Target = KC.DataAccess.Global.SQL;
[TestMethod]
[TestCategory("Unit")]
[ExpectedException(typeof(ArgumentNullException))]
public async Task ExecuteNonQueryFail1()
{
await Target.ExecuteNonQuery(null, "select 1");
}
我自己还没有机会尝试这种新的支持,但我已经读到这应该是可行的
注意:除非必须返回void(例如,对于事件处理程序),否则应该在异步方法中返回Task。任务是可等待的,因此代码更易于重用。我把这件事写进去
如果出于某种原因确实需要测试异步void方法,则需要提供自己的SynchronizationContext来捕获任何异常。请参阅的异步单元测试部分
我有几篇博客文章专门讨论异步单元测试。我为VS2010+AsyncCTP或VS11DevpReview编写了一个基本的异步单元测试项目,但我还没有机会用VS11Beta测试它。如果需要,这将是单元测试异步void方法的最简单方法 注意:当我更改目标方法以返回任务时,以及当我在测试的配置文件中启用ThrowUnservedTaskExceptions时,会发生相同的行为。您应该使用TaskEx.Delay而不是Thread.Sleep。注意,当我更改目标方法以返回任务时,也会发生相同的行为,当我在测试的配置文件中启用ThrowUnobservedTaskException时,应该使用TaskEx.Delay而不是Thread.Sleep。如果使用Wait,则不能使用ExpectedException。将测试方法设为异步任务并让它等待任务将更干净。这是VS11Beta中添加的新功能;它不在VS11DevPreview中。您可以使用[ExpectedExceptiontypeofAggregateException],但我想这还不够具体。我确实有task/await的重载,但有些SQL调用可以随时执行。这是一个空白,因为我希望能够“触发并忘记”,就像在错误日志记录或将作业提交到队列的情况下一样。好的,我按照你说的做了,它抛出了AggregateException。这似乎不如抛出的实际异常有用,但至少我可以将其分解为聚合异常。现在,我如何保证它将以fire and forget的方式运行而不需要等待结果呢?很简单:该方法不返回任何结果,因此没有什么需要等待的。等待ExecuteOnQuery…根本无法编译。但是你真的不应该创建“开火然后忘记”的方法,除非你需要。这取决于消费者是否要等到完成。如果使用wait,则不能使用ExpectedException。将试验方法简化会更干净
c任务,并让它等待任务。这是VS11Beta中添加的新功能;它不在VS11DevPreview中。您可以使用[ExpectedExceptiontypeofAggregateException],但我想这还不够具体。我确实有task/await的重载,但有些SQL调用可以随时执行。这是一个空白,因为我希望能够“触发并忘记”,就像在错误日志记录或将作业提交到队列的情况下一样。好的,我按照你说的做了,它抛出了AggregateException。这似乎不如抛出的实际异常有用,但至少我可以将其分解为聚合异常。现在,我如何保证它将以fire and forget的方式运行而不需要等待结果呢?很简单:该方法不返回任何结果,因此没有什么需要等待的。等待ExecuteOnQuery…根本无法编译。但是你真的不应该创建“开火然后忘记”的方法,除非你需要。这取决于消费者是否愿意等待,直到完成。你的逻辑是正确的,但它仍然没有抛出。请参见svick的答案。您是否确实将Target.ExecuteNonQuery的返回类型更改为Task?将其包装到任务中。运行完全不是一回事。是的,我将其更改为任务。我所寻找的只是一种测试它、检测异常并能够运行它而无需在其他地方等待它的方法。很明显,我真的想在测试中等待它。你的逻辑是正确的,但它仍然没有抛出。请参见svick的答案。您是否确实将Target.ExecuteNonQuery的返回类型更改为Task?将其包装到任务中。运行完全不是一回事。是的,我将其更改为任务。我所寻找的只是一种测试它、检测异常并能够运行它而无需在其他地方等待它的方法。很明显,我真的想等待考试结果。