我正在玩Visual Studio 11 Beta。
鉴于此代码:
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();
}
}
}
由于它是一个异步方法,异常似乎没有冒泡到调用方法。我的测试用例因此失败了:
using Target = KC.DataAccess.Global.SQL;
[TestMethod]
[TestCategory("Unit")]
[ExpectedException(typeof(ArgumentNullException))]
public void ExecuteNonQueryFail1()
{
Target.ExecuteNonQuery(null, "select 1");
}
在这种情况下,ExecuteNonQuery的验证部分显然抛出异常,我看到它在调试时抛出。
我已将测试方法更改为async,语法为 await Task.Run(()=&gt; Target.ExecuteNonQuery()),但无济于事。
问题:
答案 0 :(得分:4)
VS11 Beta对返回Task
的测试方法提供了一流的支持。
因此,如果您将签名更改为:
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");
}
(我没有机会亲自尝试这种新的支持,但我已经读过这应该有用了。)
注意:除非必须返回Task
,否则应该在async
方法中返回void
(例如,对于某个事件)处理程序)。 Task
是等待的,因此代码更具可重用性。我在my "Async and Await" intro blog post中介绍了这一点。
如果您确实需要出于某种原因测试async void
方法,则需要提供自己的SynchronizationContext
以捕获任何异常(请参阅Stephen Toub's recent blog post的“异步单元测试”部分)。
我有一些专门处理异步单元测试的博客文章(part 1,part 2)。我为VS2010 + AsyncCTP或VS11-DevPreview编写了一个基本的异步单元测试项目,但我还没有机会用VS11-Beta测试它。如果需要,这将是单元测试async void
方法的最简单方法。 [CodePlex | NuGet]
答案 1 :(得分:3)
由于您的方法返回void
,因此异常无法传播到调用代码。如果将返回类型更改为Task
,现在可以观察异常,但必须明确地执行此操作。
我认为修改调用代码的最佳方法就是调用Wait()
。如果Task
中的代码引发了异常,则Wait()
会抛出一个包含原始异常的AggregateException
。