集成测试 - 回滚复杂事务
为了集成测试的目的,我们保存数据并从 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,必须先将其关闭。*
For integration testing purpose, we are savin data&reading data back from SQL. To avoid 'trash' in the test database, it runs in a transaction and rolled back.
While running this transaction, it throws 'TransactionScope error' exception:
using (var transaction = new TransactionScope())
{
// saving (submitchanges)
// reading (linq2sql select to get saved data) // 'Transaction has aborted' was thrown
// rollback
}
When using explicit connection/transaction handling it works well - but the code is ugly.
What can I do?
Environment: .NET 3.5/C#, MSSQL2k8
Detailed exception:
System.Transactions.TransactionAbortedException : The transaction has aborted.
----> System.Transactions.TransactionPromotionException : Failure while attempting to promote transaction.
----> System.Data.SqlClient.SqlException : There is already an open DataReader associated with this Command which must be closed first.*
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我多年来一直在这个问题上挣扎。基本上有两个极端你必须选择:
请注意,我说的是“重置”,而不是“恢复”……它不必那么密集。我想出了很多方法,包括分离和重新附加规范的测试 mdf 文件(比恢复快得多,至少当时是这样)、执行数据转储重置脚本(截断或删除所有表并重置它们) )。
最近,我一直在研究 RedGate 的 Sql Compare...我仍然不确定如何将它们放在一起。但最终,我沿着事务/回滚路径一路走下去,并认为它在测试方程中引入了太多未经单元测试的代码。
I've struggled with this question for a number of years. There are basically two extremes you have to choose from:
Notice I said "reset", not "restore"...it doesn't have to be that intensive. I've come up with a number of approaches, including detaching and reattaching a canonical testing mdf file (much faster than a restore, at least it was then), executing a data dump reset script (truncating or deleting all the tables and resetting them).
Lately, I've been looking at RedGate's Sql Compare...I'm still not exactly sure how to put that together. But ultimately, I went all the way down the transaction / rollback path and decided that it introduced too much un-unit tested code into the testing equation.
如果您不测试数据库结构,那么我建议从等式中删除数据库并采用依赖注入方法。如果您使用的是 LINQ to SQL,而不是存储过程,这意味着您实际上可以控制感兴趣的数据来自何处,即在正常情况下它将是数据库,并且在测试中,它可以是预定义的对象集合。为了从数据中抽象使用,您必须使用一堆
IQuariable
属性定义数据提供程序接口/抽象类。默认实现会将它们与数据库表链接,测试实现将在内存中生成它们。您现在所要做的就是注入一个或另一个实现实例。If you are not testing DB structure, then I'd suggest removing the DB from the equation all together and go for dependency injection approach. If you are using LINQ to SQL, not stored procs, this means you may actually control where the data of interest come from, i.e. in normal circumstances it will be database, and under testing, it can be predefined collections of objects. In order to abstract usage from the data, you have to define a data provider interface/abstract class with a bunch of
IQuariable<T>
properties. The default implementation would link them with the database tables, the test implementation would generate them in memory. All you have to do now is to inject one or another implementation instance.