2008-08-22 213 views
32

今年夏天,我開發了一個基本的ASP.NET/SQL Server CRUD應用程序,單元測試是其中一個要求。當我試圖對數據庫進行測試時遇到了一些麻煩。據我瞭解,單元測試應該是:單元測試數據庫

  • 無國籍
  • 相互獨立
  • 重複相同的結果,即沒有更改保存

這些要求似乎是在每個賠率其他當爲數據庫開發時。例如,我不能測試Insert()而不確定要插入的行不存在,因此我需要先調用Delete()。但是,如果他們不在那裏呢?然後我需要先調用Exists()函數。

我最終的解決方案涉及非常大的設置函數(yuck!)和一個空的測試用例,它將首先運行,並表明安裝程序沒有問題。這是犧牲了測試的獨立性,同時保持了他們的無狀態。

我發現的另一個解決方案是將函數調用包裝在易於回滾的事務中,如Roy Osherove's XtUnit。這項工作,但它涉及另一個圖書館,另一個依賴,並且對於手頭問題的解決方案似乎有點過分。

那麼,面對這種情況,SO社區做了什麼?


tgmdbm說:

通常可以使用自己喜歡的 自動化單元測試框架 進行集成測試,這是 爲什麼有些人感到困惑,但他們 不遵循相同的規則。你是 允許涉及你的許多類 (因爲他們已經過單元測試)的具體實施 。 您正在測試您的具體 類如何相互交互,以及 與數據庫

所以,如果我讀這正確的,實在是沒有辦法有效單元測試數據訪問層。或者,數據訪問層的「單元測試」是否涉及測試,比如由類生成的SQL /命令,而與數據庫的實際交互無關?

回答

25

除了聲明表存在,包含預期的列並具有適當的約束之外,沒有真正的單元測試數據庫的方法。但這通常並不值得。

您通常不會單元測試數據庫。您通常涉及集成測試中的數據庫。

您通常使用自己喜歡的自動化單元測試框架來執行集成測試,這就是爲什麼有些人會感到困惑,但他們不遵循相同的規則。你可以參與許多類的具體實現(因爲它們已經過單元測試)。您正在測試具體類如何與數據庫和數據庫進行交互。

11

DBunit

您可以使用此工具將數據庫的狀態在給定時間導出,然後當你的單元測試,可以在的開始時自動回滾到以前的狀態試驗。我們經常在我工作的地方使用它。

5

單元測試中外部依賴的通常解決方案是使用模擬對象 - 也就是說,模仿您正在測試的真實對象的行爲的庫。這並不總是直截了當,有時需要一些獨創性,但如果你不想「自己推出」,那麼在.Net中有幾個好的(免費軟件)模擬庫。兩個馬上想到:

Rhino Mocks是一個有很好的聲譽。

NMock是另一個。

也有大量的商業模擬庫可用。編寫好的單元測試的一部分實際上就是爲你的代碼設計代碼 - 例如,通過使用有意義的接口,以便通過實現它的接口的「虛假」版本來「模擬」依賴對象,該接口的行爲卻在可預測的方式,用於測試目的。

在數據庫嘲諷中,這意味着「嘲笑」您自己的數據庫訪問層,使用返回組成表,行或數據集對象的對象來處理單元測試。

我在哪裏工作,我們通常從頭開始製作自己的模擬庫,但這並不意味着您必須這樣做。

1

你應該做的是從腳本生成的數據庫空白副本中運行測試。您可以運行測試,然後分析數據以確保它在測試運行後完全符合它的要求。那麼你只需刪除數據庫,因爲它是一次性的。這可以全部自動化,並且可以被認爲是原子動作。

4

是的,您應該重構代碼以訪問訪問數據庫的存儲庫和服務,然後可以模擬或存根這些對象,以便測試的對象不會觸及數據庫。這比存儲數據庫的狀態並在每次測試後重置它快得多!

我強烈建議Moq作爲你的模擬框架。我用過Rhino Mocks和NMock。 Moq非常簡單,解決了我與其他框架所遇到的所有問題。

2

我有同樣的問題,並得出了與其他答案相同的基本結論:不要打擾單元測試實際的數據庫通信層,但如果你想單元測試你的模型函數(以確保它們正確地拉取數據,正確地格式化數據等),使用某種虛擬數據源和設置測試來驗證正在檢索的數據。

我也發現單元測試的基本定義不適合很多Web開發活動。但這個頁面描述了一些更「高級」的單元測試的模型,並可能有助於激發一些想法,在各種情況下應用的單元測試:

Unit Test Patterns

2

我解釋說,我一直在使用這個特別的情況here技術。

其基本思想是在DAL中運用每種方法 - 聲明結果 - 並且每次測試完成後,回滾數據庫以保證數據庫乾淨(無垃圾/測試數據)。

您可能找不到「唯一」的唯一問題是我通常會執行一個完整的CRUD測試(從單元測試的角度來看不是純粹的),但這個集成測試允許您查看您的CRUD +映射代碼。通過這種方式,如果發生故障,在啓動應用程序之前您將知道(在我嘗試快速運行時爲我節省大量工作)

1

一起測試數據層和數據庫對於稍後在 項目。但是,對數據庫進行測試有其問題,主要的問題是您正在測試多個測試共享的狀態 。如果您在一次測試中將一行插入數據庫 ,則下一次測試也可以看到該行。
您需要的是回滾對數據庫所做更改的方法。
TransactionScope類足夠聰明,可以處理非常複雜的事務, 以及嵌套事務,其中您的代碼在其自己的 本地事務中調用提交。 下面是一段簡單的代碼,顯示它是多麼容易添加到您的 測試回滾能力:

[TestFixture] 
    public class TrannsactionScopeTests 
    { 
     private TransactionScope trans = null; 

     [SetUp] 
     public void SetUp() 
     { 
      trans = new TransactionScope(TransactionScopeOption.Required); 
     } 

     [TearDown] 
     public void TearDown() 
     { 
      trans.Dispose(); 
     } 

     [Test] 
     public void TestServicedSameTransaction() 
     { 
      MySimpleClass c = new MySimpleClass(); 
      long id = c.InsertCategoryStandard("whatever"); 
      long id2 = c.InsertCategoryStandard("whatever"); 
      Console.WriteLine("Got id of " + id); 
      Console.WriteLine("Got id of " + id2); 
      Assert.AreNotEqual(id, id2); 
     } 
    }