1

我正在使用 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(() => Target.ExecuteNonQuery()),但无济于事。

问题:

  • ExecuteNonQuery 是否完全抛出异常?
  • 为什么 ExecuteNonQueryFail1 没有看到异常?
  • 如何更改测试方法或方法本身,以正确处理异常并通过测试用例,而不放弃方法的异步性质?
4

2 回答 2

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是可等待的,因此代码更具可重用性。我在“Async and Await”介绍性博文中对此进行了介绍。

如果async void出于某种原因确实需要测试方法,则需要提供自己的方法来捕获任何异常(请参阅Stephen Toub 最近的博客文章SynchronizationContext的“异步单元测试”部分)。

我有几篇专门讨论异步单元测试的博文(第 1部分,第 2 部分)。我为 VS2010+AsyncCTP 或 VS11-DevPreview 编写了一个基本的异步单元测试项目,但我还没有机会使用 VS11-Beta 对其进行测试。如果需要,这将是对方法进行单元测试的最简单方法async void[CodePlex | NuGet]

于 2012-03-03T22:11:46.110 回答
3

由于您的方法返回void,因此异常无法传播到调用代码。如果您将返回类型更改为Task,您现在可以观察到异常,但您必须明确地执行此操作。

我认为修改调用代码的最好方法就是调用Wait(). 如果抛出异常中的代码TaskWait()将抛出一个AggregateException包含原始异常的代码。

于 2012-03-03T13:36:12.213 回答