【问题标题】:EF4.1+Code First: Testing with transactionsEF4.1+代码优先:使用事务进行测试
【发布时间】:2012-04-30 20:56:45
【问题描述】:

在研究 EF 和 Code First 时,我不久前提出了一个问题 (ref this thread),以提醒您如何防止测试相互重叠。我想为数据库播种,并且对每个测试类都这样做(使用 MSTest):

  public class CustomerSmokeTests {
    private const string CONNECTION_STRING = "server=localhost;database=CPT_CustomerDataSync_SmokeTests;uid=sa;pwd=Password1!;";

    private DatabaseFactory _dbfactory;
    private CustomerCacheContext _customerContext;

    [TestInitialize]
    public void Setup() {
      // set initializer to create new DB
      Database.SetInitializer(new SmokeTestCreateDbWithDataIfNotExists());
      Database.SetInitializer(new SmokeTestDropCreateDbWithDataAlways());

      // create new DB connection to local SQL Server
      _dbfactory = new DatabaseFactory(CONNECTION_STRING);

      // connect to DB to auto generate it
      _customerContext = _dbfactory.GetDataContext();
    }

    [TestCleanup]
    public void Cleanup() {
      _customerContext.Dispose();
      _dbfactory.Dispose();
    }

    // tests
}

但是这里的问题是每个测试都会创建/拆除数据库(不理想,因为它们相互重叠并失败......如果您单独运行测试,它们都会按需要通过......而且这会大大减慢测试)。

一个good solution was to instead wrap them up in TransactionalScopes,但是我想确保在测试运行开始时,使用种子信息重新生成数据库(因为种子在我的开发人员开发的测试中发生变化)。

执行此操作的蛮力方法是在测试初始化​​中创建某种处理程序,它会检查数据库是否是最近创建的,如果不是,则使用种子信息创建它。如果不是,它将忽略该步骤。然后它会创建一个 TransactionalScope() 将在测试清理中回滚。

但是有没有更好的方法来处理这个问题?对这种蛮力方法有过度设计的感觉...想法?

【问题讨论】:

  • 实体框架已经在 savechanges 上使用了幕后事务

标签: unit-testing entity-framework-4.1 ef-code-first


【解决方案1】:

Marvel 的回复让我朝着正确的方向思考……让它发挥作用,在这里解释有点长,所以我在这里写了博客:http://www.andrewconnell.com/blog/archive/2012/05/02/isolating-integration-tests-with-ef4-x-code-first-amp-mstest.aspx

【讨论】:

    【解决方案2】:

    通常,这些测试与持续集成服务器高度集成,每次检查。因此,我认为如果您可以将 dbCreation 测试作为测试设置中的第一个测试来订购会更好,因为它会创建具有所有必要映射的 db。之后,在第一次测试时创建它,其他测试可以在您的基础 TestFixture 类中使用 Transactionscope 来满足您现在的使用方式,并且您的集成测试可以有效地工作,因为您没有使用 TestInitialize 和 TestCleanup 创建数据库。

    public class BaseTestFixture
    {
    
    TransactionScope transactionScope;
    
        [TestInitialize]
        public void InitializeTests()
        {            
    
            if (IsTransactionScopeNeeded)
            {
                transactionScope = new TransactionScope();
            } 
        }
    
        [TestCleanup]
        public void CleanUp()
        {
            if (transactionScope != null)
                transactionScope.Dispose();
    
        }
    

    }

    public class DbContextTests : BaseTestFixture
    {
    
        protected override bool IsTransactionScopeNeeded
        {
            get
            {
                return false;
            }
        }
    
        //This test should run first 
        [TestMethod]
        public void CreateDatabase_DatabaseNotExistedOrObselete_DatabaseCreated()
        {
        }
    }
    

    【讨论】:

    • 这需要创建有序测试...是吗?我试图避免有序测试,因为我们使用的测试运行器无法识别它们。
    • 我认为在您的构建服务器中,您可以通过给出命令而不是使用有序的测试列表来执行 DbContext 测试。 Rest 可以通过使用有序的测试列表来执行
    • -1:有序测试anti-pattern
    猜你喜欢
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    • 2011-08-12
    • 2011-10-02
    • 2020-05-12
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多