Entity framework 使用事务处理与实体框架集成测试的缺点

Entity framework 使用事务处理与实体框架集成测试的缺点,entity-framework,transactions,entity-framework-6.1,Entity Framework,Transactions,Entity Framework 6.1,我正在寻找一种快速的方法来清理我的数据表,使用EF进行集成测试 每个人似乎都会围绕其测试方法包装一个事务,并在测试后处理该事务 这样,数据就不会写入表中 新的插入自动ID等功能仍在运行,但我问自己,与.commit()事务相比,这种方法是否真的可靠 使用这种方法是否有任何缺点,因为它似乎不是一个真正的集成测试,因为数据库从未接触过 或者换言之,是否存在使用不带commit()的事务不会作为异常弹出的错误场景 更新 public abstract class IntegrationTestsBas

我正在寻找一种快速的方法来清理我的数据表,使用EF进行集成测试

每个人似乎都会围绕其测试方法包装一个事务,并在测试后处理该事务

这样,数据就不会写入表中

新的插入自动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");          
        }
}
因为数据库从未被触碰过

肯定是感动了。事务中发生的一切都发生在数据库中。标识值和序列(如果有)递增、触发、检查引用约束等。唯一的问题是,它是孤立发生的,最终所有内容(递增的标识和序列除外)都被还原

使用这种方法有什么缺点吗

不是真的。我在自己的代码中广泛使用了这种方法,它有很多优点。绿色测试提供了非常高的保证级别。使用模拟上下文和
DbSet
的“真实”单元测试,我永远不会感到安全(尽管我在许多其他事情上使用单元测试)

但是有一些限制你应该注意

  • 标识/序列值不是确定性的,因此不能断言它们。正如我所说,这些值不会被回滚。如果您在该区域确实需要断言,您可以在每次测试后重置标识/序列
  • 我们无法用这种方法测试并发性问题
  • 如果没有DTC,您无法打开到另一个数据库的连接,或者如果其连接字符串在最细微的细节(例如,不同的应用程序名称或不同的MARS设置)上存在差异,甚至无法打开到同一个数据库的连接。在应用程序代码中,这是可能的,因为这些不同的调用不会包装在
    TransactionScope
    中。因此,可能不是所有的应用程序路径都可以通过这种方式轻松测试
  • 开发人员应该使用自己的测试数据库副本。如果多个开发人员(可能还有一个构建服务器)在同一个数据库上运行测试,他们可能会互相死锁

唯一真正的区别在于您没有测试并发性。因此,当您需要(而且您也需要!)时,您将更改开始事务/回滚方法。此外,还原备份和删除数据库在测试开始/结束时只有几行代码。@bubi还原数据库比context.datebase.Create()快?如果可以使用空数据库启动测试,也可以使用Create()。我不知道它是否更快可能取决于表/字段/关系/DBMS的数量。。。另外,可能是某些EF提供程序不支持Create()。在我的例子中,我使用Microsoft Access测试EF,并且提供程序支持codefirst迁移,但不支持独立于该方法的Create(),您应该避免测试自动编号字段。几个月后,由于某种原因,他们总是停止工作:)当我给他们重新播种时,他们应该总是这样。我不测试汽车公司等。。。这应该是设计好的。我只依赖于某个Id=1,因为如果有什么问题,我知道autoinc坏了/重新设定种子不起作用,干净的表/事务内容不起作用。每次测试我都会在表中有一行,这一行必须相互独立。然后我感觉自己陷入了身份不重置的陷阱。我的测试各自独立运行,但当我一起运行它们时,由于错误的Id导致并发错误。我需要让每个测试有一个新的起始Id,否则我的多个测试会有无人能猜到的假设,这将是一个糟糕的依赖性。那么多个用户不能在没有死锁的情况下提交这些内容并安全地运行测试?但如果你问我,这是一个典型的情况。并发在这个应用程序中不起任何作用。因为TransactionScope的隔离级别和测试运行时间相对较长,所以可能会发生死锁。通常情况下,这不会发生得这么快。每个开发人员拥有自己的数据库的另一个优点是,他们可以在不打扰其他人的情况下试验新的数据库内容。如果您需要标识值(我不建议使用自然键),则必须在每次测试后运行DBCC CHECKIDENT(reseed)。哦,自然键与代理键的讨论与人类一样古老;-)我用我现在使用的最后一个代码更新了我的问题,效果很好。谢谢,祝你玩得开心,得到50分;-)我以为我做到了,然后有什么事情发生了;-)