我应该如何设置集成测试以将测试数据库与Entity Framework一起使用?

时间:2012-12-13 09:53:29

标签: c# asp.net-mvc entity-framework ef-code-first integration-testing

我正在为应用程序编写集成测试,但无法找到有关如何为我的集成套件设置测试数据库的最佳实践。我正在使用实体框架代码优先处理ASP.NET MVC4应用程序。

我可以确认我的测试项目中的测试默认与我的机器上的本地开发数据库通信。这并不理想,因为我希望每次运行测试时都有一个新的数据库。

如何设置测试项目以便我的测试与单独的实例通信?我假设可以设置SQL Server Compact Edition实例,但我不知道如何配置它。

3 个答案:

答案 0 :(得分:24)

非常感谢@Justin和@Petro的回答,这对我帮助很大。我提出的解决方案是您建议的技术的组合。下面描述的解决方案为每次测试运行提供了一个新数据库,并为每个测试提供了一个单独的事务。

我在我的测试项目的App.config中为我的测试数据库添加了一个连接字符串:

  <connectionStrings>
    <add name ="TestDatabase"
     providerName="System.Data.SqlClient"
     connectionString="Data Source=(LocalDb)\v11.0;Database=TestDatabase;Integrated Security=True"/>
  </connectionStrings>

我为集成测试创建了一个基类,以提供设置和拆卸。安装程序实例化上下文,如果它尚不存在则创建数据库并启动事务。 Teardown回滚交易。

public class EntityFrameworkIntegrationTest
{
    protected MyDbContext DbContext;

    protected TransactionScope TransactionScope;

    [TestInitialize]
    public void TestSetup()
    {
        DbContext = new MyDbContext(TestInit.TestDatabaseName);
        DbContext.Database.CreateIfNotExists();
        TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
    }

    [TestCleanup]
    public void TestCleanup()
    {
        TransactionScope.Dispose();
    }
}

最后,我有一个类在所有测试运行后负责删除数据库:

[TestClass]
public static class TestInit
{
    // Maps to connection string in App.config
    public const string TestDatabaseName = "TestDatabase";

    [AssemblyCleanup]
    public static void AssemblyCleanup()
    {
        Database.Delete(TestDatabaseName);
    }
}

我应该补充一点,我发现this blog post about Entity Framework有助于更深入地了解实体框架在会议期间所做的事情。

答案 1 :(得分:5)

只需在单元测试项目的app.config中设置一个指向新数据库实例的连接字符串。

然后,您可以使用测试类中的初始化和清理方法来创建和删除数据库。

连接字符串就是常见的,例如

<add name="UnitTestDBConnection" connectionString="Data Source=(local);Initial Catalog=UnitTestDB;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>

然后创建数据库,每次测试一次,你可以这样做:

    YourContext _ctx;

    [TestInitialize]
    public  void Initiaslise()
    {

        YourNameDbInitialise initialiser = new YourNameDbInitialiseForTest();
        Database.SetInitializer(initialiser);

        _ctx = new YourNameContext();

        initialiser.InitializeDatabase(_ctx);         
    }

这将在每次测试结束时删除

    [TestCleanup]
    public  void Cleanup()
    {
        Database.Delete("YourName");
    }

答案 2 :(得分:5)

如果您使用的是NUnit,则可以使用Setup/Teardown属性TransactionScope来不对数据库进行更改:

[SetUp]
public void SetUp()
{
    transaction = new TransactionScope();
}

[TearDown]
public void TearDown()
{
    if(transaction != null) 
       transaction.Dispose();
}

如果您正在使用其他单元测试框架,则它应该具有类似的属性。我建议为所有集成测试装置创建基类DbItegrationTest,这样如果从这个类派生,所有测试方法都不会对数据库进行提交。

要为其他数据库配置Entity Framework,请覆盖测试程序集中的db连接字符串。