集成测试 - 回滚复杂的事务

时间:2011-01-19 14:17:05

标签: c# .net sql linq transactionscope

出于集成测试的目的,我们提供数据并从SQL读取数据。为了避免测试数据库中的“垃圾”,它在事务中运行并回滚。

在运行此事务时,它会抛出'TransactionScope错误'异常:

using (var transaction = new TransactionScope()) 
{
    // saving (submitchanges)
    // reading (linq2sql select to get saved data)   // 'Transaction has aborted' was thrown

    // rollback
} 

使用显式连接/事务处理时,它运行良好 - 但代码很难看。

我该怎么办?

环境:.NET 3.5 / C#,MSSQL2k8

详细例外:

System.Transactions.TransactionAbortedException:事务已中止。   ----> System.Transactions.TransactionPromotionException:尝试提升事务时失败。   ----> System.Data.SqlClient.SqlException:已经有一个与此命令关联的打开DataReader,必须先关闭它。*

2 个答案:

答案 0 :(得分:1)

多年来我一直在努力解决这个问题。基本上有两个极端你必须选择:

  1. 使用特定于测试的事务和回滚代码来混淆代码,这很容易出错,并且
  2. 在每次测试之间完全重置数据库。
  3. 注意我说“重置”,而不是“恢复”......它不一定非常密集。我提出了许多方法,包括分离和重新附加规范测试mdf文件(比恢复快得多,至少在那时),执行数据转储重置脚本(截断或删除所有表并重置它们) )。

    最近,我一直在关注RedGate的Sql Compare ......我仍然不确定如何把它放在一起。但最终,我一直沿着事务/回滚路径走下去,并决定在测试方程中引入太多未经过单元测试的代码。

答案 1 :(得分:1)

如果您没有测试数据库结构,那么我建议将数据库从等式中删除,并采用依赖注入方法。如果您使用的是LINQ to SQL,而不是存储过程,这意味着您实际上可以控制感兴趣的数据来自何处,即在正常情况下它将是数据库,并且在测试中,它可以是预定义的对象集合。为了从数据中抽象使用,您必须使用一堆IQuariable<T>属性定义数据提供程序接口/抽象类。默认实现将它们与数据库表链接,测试实现将在内存中生成它们。您现在要做的就是注入一个或另一个实现实例。