EF4.1 + Code First:使用事务进行测试

时间:2012-04-30 20:56:46

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

研究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
}

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

A good solution was to instead wrap them up in TransactionalScopes,但我想确保在测试运行开始时,使用种子信息重新生成数据库(因为种子会随着我的开发人员开发测试而更改)。

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

但是有更好的方法来解决这个问题吗?这个蛮力的appraoch ...想法得到了过度工程化的感觉?

2 个答案:

答案 0 :(得分:2)

Marvel的回应让我思考正确的方向......让它运转起来,在这里解释有点长,所以我在这里写博客:http://www.andrewconnell.com/blog/archive/2012/05/02/isolating-integration-tests-with-ef4-x-code-first-amp-mstest.aspx

答案 1 :(得分:-1)

通常,这些测试与Continuous Integration服务器高度集成,每次检查都是如此。所以我认为如果您可以将dbCreation测试作为测试设置中的第一个测试进行排序会更好,因为它会创建具有所有必要映射的数据库。之后,在第一次测试时创建它,其他测试可以在您的基本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()
    {
    }
}