测试不使用事务的SQL方法?

时间:2017-04-10 19:26:42

标签: c# sql-server

假设我有一个如下所示的数据库方法:

public void insertRow(SqlConnection c)
{
    using (var cmd = new SqlCommand("insert into myTable values(@dt)",c))
    {
        cmd.Parameters.Add(new SqlParameter("@dt",DbType.DateTime)).Value = DateTime.Now;
        cmd.ExecuteNonQuery();
    }
}

现在假设我想测试这个方法。因此,我编写了一个测试用例,尝试将此方法包装在事务中,以便在测试插入结果后可以回滚更改:

public void testInsertRow()
{
    SqlConnection c = new SqlConnection("connection.string.here");
    SqlTransaction trans = c.BeginTransaction();
    insertRow();
    // do something here to evaluate what happened, e.g. query the DB
    trans.Rollback();
}

然而,这无效,因为:

  

当分配给命令的连接处于挂起的本地事务中时,ExecuteNonQuery要求命令具有事务。该命令的Transaction属性尚未初始化。

有没有办法实现这一点,无需重写每个数据库方法来接受事务,然后重写每个调用以将null传递给事务的方法?

例如,这可行:

public void insertRow(SqlConnection c, SqlTransaction t)
{
    using (var cmd = new SqlCommand("insert into myTable values(@dt)",c))
    {
        if (t != null) cmd.Transaction = t;
        cmd.Parameters.Add(new SqlParameter("@dt",DbType.DateTime)).Value = DateTime.Now;
        cmd.ExecuteNonQuery();
    }
    c.Close();
}

但是,我必须重写每次调用数据库方法以包含null参数,或者为每个自动传递null的数据库方法写入覆盖签名,例如

public void insertRow(SqlConnection c) { insertRow(c, null); }

允许基于事务的数据库调用测试的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

您可以使用TransactionScope自动将连接添加到交易中

public void testInsertRow()
{
    using(TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        SqlConnection c = new SqlConnection("connection.string.here");
        insertRow(c);
        // do something here to evaluate what happened, e.g. query the DB

        //do not call scope.Complete() so we get a rollback.
    }   
}

现在,如果您运行多个并行测试,这将导致测试相互阻塞。如果您将数据库设置为支持它,则可以执行快照隔离,因此并发测试的更新不会互相锁定。

public void testInsertRow()
{
    using(TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, 
                                                        new TransactionOptions(IsolationLevel = IsolationLevel.Snapshot))
    {
        SqlConnection c = new SqlConnection("connection.string.here");
        insertRow(c);
        // do something here to evaluate what happened, e.g. query the DB

        //do not call scope.Complete() so we get a rollback.
    }   
}
相关问题