使用事务处置和 entity framework 集成测试的缺点
Downside of using transaction dispose with entity framework integration testing
我正在寻找一种快速方法来清理我的 tables 数据,使用 EF 进行集成测试。
每个人似乎都围绕其测试方法包装事务并在测试后处理事务。
这样数据永远不会写入 table。
插入的新自动 id 之类的东西仍然有效,但我问自己,与 .commit() 事务相比,这种方法是否真的可靠。
使用这种方法是否有任何缺点,它似乎不是真正的集成测试,因为从未接触过数据库...
或者换句话说,是否存在使用没有 commit() 的事务不会作为异常弹出的错误场景?
更新
public abstract class IntegrationTestsBase
{
protected TransactionScope TransactionScope;
public abstract void TestSetup();
protected void InitTestSetupOnTable(string tableName)
{
TransactionScope = new TransactionScope();
using (var context = new TGBContext())
{
var cmdCommand = string.Format("DBCC CHECKIDENT ({0}, RESEED, 1)", tableName);
context.Database.ExecuteSqlCommand(cmdCommand);
context.SaveChanges();
}
}
[TestCleanup]
public void TestCleanup()
{
TransactionScope.Dispose();
}
}
[TestClass]
public class MyTests : IntegrationTestsBase
{
[TestInitialize]
public override void TestSetup()
{
base.InitTestSetupOnTable("MyTableName");
}
}
as the database is never touched
肯定是被感动了。事务中发生的一切都发生在数据库中。身份值和序列(如果有的话)递增,触发器触发,引用约束被检查等等。唯一的事情是,它是孤立发生的,最后一切(递增的身份和序列除外)都被还原。
Are there any downsides of using this approach?
不是真的。我在自己的代码中广泛使用这种方法,它有很多优点。绿色测试提供了非常高水平的保证。我永远不会对使用模拟上下文和 DbSet
的 "real" 单元测试感到安全(尽管我对许多其他事情使用单元测试)。
但是您应该注意一些限制。
- 标识/序列值不是确定性的,因此您不能断言它们。正如我所说,这些值不会回滚。如果你真的需要这方面的断言,你可以在每次测试后重新设置identities/sequences。
- 我们永远无法通过这种方法测试并发问题。
- 如果连接字符串在最细微的细节上有所不同(例如,不同的应用程序名称或不同的 MARS 设置),则无法打开与另一个数据库的连接,甚至无法打开与同一数据库的连接,而不会启动 DTC。在应用程序代码这是可能的,因为这些不同的调用不会包含在
TransactionScope
中。因此,也许并非所有应用程序路径都可以通过这种方式轻松测试。
- 开发人员应使用自己的测试数据库副本。如果多个开发人员(可能还有构建服务器)运行 在同一个数据库上进行测试,他们可能会彼此死锁。
我正在寻找一种快速方法来清理我的 tables 数据,使用 EF 进行集成测试。
每个人似乎都围绕其测试方法包装事务并在测试后处理事务。
这样数据永远不会写入 table。
插入的新自动 id 之类的东西仍然有效,但我问自己,与 .commit() 事务相比,这种方法是否真的可靠。
使用这种方法是否有任何缺点,它似乎不是真正的集成测试,因为从未接触过数据库...
或者换句话说,是否存在使用没有 commit() 的事务不会作为异常弹出的错误场景?
更新
public abstract class IntegrationTestsBase
{
protected TransactionScope TransactionScope;
public abstract void TestSetup();
protected void InitTestSetupOnTable(string tableName)
{
TransactionScope = new TransactionScope();
using (var context = new TGBContext())
{
var cmdCommand = string.Format("DBCC CHECKIDENT ({0}, RESEED, 1)", tableName);
context.Database.ExecuteSqlCommand(cmdCommand);
context.SaveChanges();
}
}
[TestCleanup]
public void TestCleanup()
{
TransactionScope.Dispose();
}
}
[TestClass]
public class MyTests : IntegrationTestsBase
{
[TestInitialize]
public override void TestSetup()
{
base.InitTestSetupOnTable("MyTableName");
}
}
as the database is never touched
肯定是被感动了。事务中发生的一切都发生在数据库中。身份值和序列(如果有的话)递增,触发器触发,引用约束被检查等等。唯一的事情是,它是孤立发生的,最后一切(递增的身份和序列除外)都被还原。
Are there any downsides of using this approach?
不是真的。我在自己的代码中广泛使用这种方法,它有很多优点。绿色测试提供了非常高水平的保证。我永远不会对使用模拟上下文和 DbSet
的 "real" 单元测试感到安全(尽管我对许多其他事情使用单元测试)。
但是您应该注意一些限制。
- 标识/序列值不是确定性的,因此您不能断言它们。正如我所说,这些值不会回滚。如果你真的需要这方面的断言,你可以在每次测试后重新设置identities/sequences。
- 我们永远无法通过这种方法测试并发问题。
- 如果连接字符串在最细微的细节上有所不同(例如,不同的应用程序名称或不同的 MARS 设置),则无法打开与另一个数据库的连接,甚至无法打开与同一数据库的连接,而不会启动 DTC。在应用程序代码这是可能的,因为这些不同的调用不会包含在
TransactionScope
中。因此,也许并非所有应用程序路径都可以通过这种方式轻松测试。 - 开发人员应使用自己的测试数据库副本。如果多个开发人员(可能还有构建服务器)运行 在同一个数据库上进行测试,他们可能会彼此死锁。