17

我正在爲應用程序編寫集成測試,並且無法找到任何有關如何爲集成套件設置測試數據庫的最佳實踐。我正在使用基於代碼的實體框架開發ASP.NET MVC4應用程序。我應該如何設置我的集成測試以在Entity Framework中使用測試數據庫?

我可以確認我的測試項目中的測試默認與我的機器上的本地開發數據庫交談。這並不理想,因爲每次運行測試時都想要新的數據庫。

如何設置我的測試項目,以便我的測試與單獨的實例通話?我假設可以設置一個SQL Server Compact Edition實例,但我不確定如何配置它。

+0

Jimmy Bogard撰寫的這篇文章是關於這個主題的一篇很好的文章:[在集成測試中隔離數據庫數據](http://lostechies.com/jimmybogard/2012/10/18/isolating-database-data-in-集成的測試/)。 –

回答

21

非常感謝@Justin和@Petro的回答,這對我的幫助非常大。我提出的解決方案是您所建議的技術的組合。下面介紹的解決方案爲每次測試運行提供一個新的數據庫,併爲每個測試提供一個單獨的事務。

我在測試項目的App.config中添加一個連接字符串我的測試數據庫:

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

我創建了一個基類,我的集成測試,爲客戶提供安裝和拆卸。安裝程序實例化上下文,創建數據庫(如果尚不存在)並啓動事務。拆解回滾交易。

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

我會把DbContext.Database.CreateIfNotExists();在[AssemblyInitialize] – Elisabeth

+0

歸因於一個方法如果我將名稱傳遞給我的DbContext的構造函數,則不會發生任何情況。它仍然使用數據庫的默認配置。爲什麼這對你而言並不適合我?奇怪的。 –

+0

MyDbContext類在哪裏?那是什麼樣子? – Sonofblip

4

只需在您的單元測試項目的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"); 
    } 
+0

謝謝。你可以在你的答案中分享一些代碼,說明這是如何完成的嗎?如何創建新的數據庫,以及如何確保提供正確的連接字符串? – rouan

+1

查看上面的編輯 –

3

結束刪除。如果您正在使用NUnit ,您可以使用Setup/Teardown屬性與TransactionScope不承諾您的變更數據庫:

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

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

如果您使用的是其他單元測試框架,它應該具有相似的屬性。我建議爲所有集成測試裝置創建一個基類DbItegrationTest,所以如果你從這個類派生所有的測試方法將不會提交數據庫。

要爲其他數據庫配置Entity Framework,請在測試程序集中重寫db連接字符串。

+1

我寧願爲我的測試使用完全不同的數據庫。使用相同的數據庫意味着它可能包含種子數據,並且如果在測試運行時由於某種原因正在使用該應用程序,該數據可能會改變。使用單獨的數據庫還可以測試我的遷移工作是否正常。 – rouan

+3

您可以使用其他數據庫進行測試。這只是更新你的測試程序集的app.config中的連接字符串。使用與您的MVC應用程序中相同的連接字符串名稱,但更新數據庫名稱/憑證等。如果您的測試程序集沒有app.config,則可以手動添加它。 –