【问题标题】:Integration tests - Rollbacking complex transactions集成测试 - 回滚复杂事务
【发布时间】:2011-01-19 14:17:04
【问题描述】:

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

在运行此事务时,它会抛出“TransactionScope error”异常:

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 与此命令关联,必须先关闭。*

【问题讨论】:

  • 正如您在详细信息中看到的那样,问题在于在该连接中打开了多个数据读取器。你可以在 using 中使用 try-catch 捕获异常吗?你真的在 using 子句中执行 transaction.rollback 吗?
  • 你在哪里看到TransactionScope?因为示例中没有...
  • 您是否在事务中打开了多个数据库连接?它将需要 MSDTC。
  • @Mrnka:是的,据我所知,MSDTC 已启用。

标签: c# .net sql linq transactionscope


【解决方案1】:

多年来,我一直在为这个问题苦苦挣扎。基本上有两种极端情况可供您选择:

  1. 用测试特定事务和回滚代码弄乱您的代码,这很容易出错,并且
  2. 在每次测试之间完全重置数据库。

请注意,我说的是“重置”,而不是“恢复”……它不必那么密集。我想出了许多方法,包括分离和重新附加规范的测试 mdf 文件(比还原快得多,至少当时是这样),执行数据转储重置脚本(截断或删除所有表并重置它们)。

最近,我一直在查看 RedGate 的 Sql Compare...我仍然不确定如何将它们组合在一起。但最终,我一直沿着事务/回滚路径走下去,并认为它在测试方程式中引入了太多未经单元测试的代码。

【讨论】:

  • 测试中的代码不应包含任何特定于测试的检查,否则如果这违反了 TDD 的定义,则测试应测试代码,而代码不应知道或区分正常执行和测试之间的任何内容。跨度>
  • 正是……这就是为什么我最终放弃了这位评论者所追求的解决方案。
  • Davide:这个测试不在单元测试分支中,而是在集成测试中。这就是原因 - 我使用 SQL 来测试 SQL...
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 2011-07-07
    相关资源
    最近更新 更多