c# - 单元测试异步方法 C#

标签 c# unit-testing asynchronous ado.net async-await

我有问题)

我尝试在我的 C# 代码中重现类似几个 sp(存储过程)调用的东西,但我想以异步方式进行。

TSQL 示例: (执行 sp @key = 15072000173475;执行 sp @key = 15072000173571;...执行 sp @key = n;)

[TestClass]
public class UnitTestNomenclature {
    [TestMethod]
    public void ParallelSQLMethod() {
        Task scropeTasks = null;
        //real amount is more then 1500
        long[] keys = new long[] {15072000173475,15072000173571 ... n };

        try {
            var tasks = keys.Select( i =>  Task.Run(async () => { await RunStoredProc(i); }));
            scropeTasks =  Task.WhenAll(tasks);

            scropeTasks.Wait();
        } catch (Exception ex) {
            Debug.WriteLine("Exception: " + ex.Message);

            Debug.WriteLine("IsFaulted: " + scropeTasks.IsFaulted);
            foreach (var inx in scropeTasks.Exception.InnerExceptions) {
                Debug.WriteLine("Details: " + inx.Message);
            }
        }

        Assert.AreEqual(1, 1);
    }

    public async Task RunStoredProc(long scollNumbParam) {
        const string strStoredProcName = @"[dbo].[sp]";
        using (SqlConnection conn = new SqlConnection(@"data source=SERVER;initial catalog=Db;integrated security=True;Trusted_Connection=Yes;")) {
            await conn.OpenAsync();
            Debug.WriteLine("============================================ Connection is open: ==============================================");

            // info
            Debug.WriteLine(String.Format("Connection: {0}", conn.ClientConnectionId));
            Debug.WriteLine(String.Format("State: {0}", conn.State.ToString()));

            using (SqlCommand cmd = new SqlCommand(strStoredProcName, conn) { CommandTimeout = 120, CommandType = CommandType.StoredProcedure }) {

                SqlParameter scrParam = new SqlParameter() {
                    ParameterName = "@KEYKRT",
                    Value = scollNumbParam,
                    SqlDbType = SqlDbType.BigInt
                };
                cmd.Parameters.Add(scrParam);

                Debug.WriteLine("Start of Proccesing: " + scollNumbParam);
                await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
                Debug.WriteLine("End of Proccesing: " + scollNumbParam);

            }
        }

        Debug.WriteLine("============================================ Connection is closed: ==============================================");
    }
}

这是我在输出窗口中得到的:

========== Connection is open: ========
Connection: 5be9c681-6eb5-422f-a22c-b49689a2d912
State: Open
Start of Proccesing: 15072000173475
========== Connection is open: ==========
Connection: cfb66041-6646-4b56-be1c-2afb26a18cb8
State: Open
Start of Proccesing: 15072000173571
.....
End of Proccesing: 15072000173475
=========== Connection is closed: =========
End of Proccesing: 15072000173571
=========== Connection is closed: =========

....

A timeout occurred while waiting for memory resources to execute the query in resource pool 'default' (2). Rerun the query.
Actual error number: 8645
Actual line number: 98

还调试说连接池溢出 我认为连接不适当处理的主要原因,但我如何通过异步实现它?

如果我尝试在声明异步任务之前只打开一个连接并将其传递给我的 RunStoredProc 方法,那么我会得到connection doesn't support MultipleActiveResultSets

using (SqlConnection conn = new SqlConnection(@"data source=SERVER;initial catalog=Db;integrated security=True;Trusted_Connection=Yes;)) {

                    conn.OpenAsync();
                    var tasks = keys.Select(i => Task.Run(async () => { await RunStoredProc(i, conn); }));
                    scropeTasks = Task.WhenAll(tasks);

                    scropeTasks.Wait();
                }

                Debug.WriteLine("========== Connection is closed: ==========");

这是我在输出窗口中得到的:

Connection: 5be9c681-6eb5-422f-a22c-b49689a2d912
State: Open
Start of Proccesing: 15072000173475
======= Connection is open: =============
Connection: cfb66041-6646-4b56-be1c-2afb26a18cb8
State: Open
Start of Proccesing: 15072000173571
========= Connection is open: =========

最佳答案

您有 1500 个左右的任务同时执行,并且还混合了异步和阻塞调用(如 .Wait),这可能会导致死锁。

使测试异步并尽量避免 async void 除非它在事件处理程序上。

尝试按顺序迭代它们。这将花费更长的时间,但至少连接将得到妥善处理,以免资源过载。您也可以考虑以合理的规模分批进行。

[TestMethod]
public async Task ParallelSQLMethod() {
    //real amount is more then 1500
    var keys = new long[] { 
        15072000173475, 
        15072000173571, 
        //....., n
    };
    var tasks = keys.Select(i => RunStoredProc(i));
    var batchSize = 50; //Or smaller

    //run tasks in batches
    var sequence = tasks;
    while (sequence.Any()) {
        var batch = sequence.Take(batchSize);
        sequence = sequence.Skip(batchSize);

        await Task.WhenAll(batch);
    }
}

关于c# - 单元测试异步方法 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45099003/

相关文章:

c# Xunit,Assert.Throws 在引发预期异常时失败

javascript - 带有小初始脚本和异步加载所有其他脚本的 Webpack

php - 在 AngularJS 中使用 ngRepeat 的控制台出错

c# - 无法运行 MBUnit 单元测试,没有运行按钮/菜单

C# 泛型 - 为什么在以这种方式处理类型参数时需要显式转换?

c# - 静态方法没有返回值

c# - sql本地数据库连接

javascript - AsyncTestCompleter Browserify Angular2 HTTP 模拟测试

javascript - Nodejs中如何处理异步事务

c# - 不同 SQL Server 架构上的 Linq2sql