2009-10-21 104 views
0

我是單元測試新手,認爲我可能已經把自己挖到了一個角落。單元測試和主鍵

在你的單元測試中,處理主鍵的更好方法是什麼?

希望一個例子會畫出一些上下文。如果創建一個對象的多個實例(讓我們說人)。

我的單元測試是測試正在創建的正確關係。

我的代碼是創建荷馬,他的孩子巴特和麗莎。他還有一個朋友巴尼,卡爾&萊尼。

我用接口分離了我的數據層。我的首選是保持主鍵簡單。例如在保存時,Person.ProductID = new Random()。Next(10000);而不是說Barney.PersonID = 9110 Homer.PersonID = 3243等

主鍵是什麼都沒關係,它只需要是唯一的。

任何想法???

編輯:

對不起,我沒有明確表態。我的項目設置爲使用Dependency Injection。數據層是完全獨立的。我的問題的焦點是,什麼是實用的?

+1

您是否生成自己的主鍵?還是你讓DB爲你生成它們? – 2009-10-21 03:40:00

+1

數據庫在插入時生成它 – 2009-10-21 03:54:07

回答

3

我有一個名爲「唯一」的類,它產生獨特的對象(字符串,整數等)。它通過保持一個內部靜態計數器確保它們每次測試都是獨一無二的。該計數器值每生成一個密鑰都會增加,並以某種方式包含在密鑰中。

所以當我設置了我的測試

var Foo = { 
    ID = Unique.Integer() 
} 

我喜歡這個,因爲它傳達的價值是不是這個測試,只是唯一重要的。

我有一個類似的'一些',不保證唯一性。當我需要測試的任意值時,我使用它。它對枚舉和實體對象很有用。

這些都不是線程安全的或任何類似的東西,它嚴格的測試代碼。

+0

Cha-ching!這就是我所追求的。謝謝! – 2009-10-21 21:43:15

0

爲什麼使用隨機數?關鍵問題的數值?我只是在數據庫中使用一個序列並調用nextval。

1

考慮使用GUID。它們在空間和時間上是獨一無二的,這意味着即使兩臺不同的計算機在相同的時間點產生它們,它們也會不同。換句話說,他們保證是獨一無二的。隨機數字永遠不會好,有相當大的碰撞風險。

可以使用靜態類和方法生成GUID:

Guid.NewGuid(); 

假設這是C#。

編輯:

另一件事,如果你只是想產生大量的測試數據,而不必手工編寫代碼,或寫循環一堆,看看NBuilder。開始使用可能有點困難(帶有方法鏈接的Fluent方法對於可讀性來說並不總是更好),但它是創建大量測試數據的好方法。

+0

使用Guid將會矯枉過正,而且我無法控制數據類型。但我會嘗試NBuilder! – 2009-10-21 04:01:19

+0

使用Guids是商品數據庫和廉價性能時代的新興最佳實踐。它不再過度殺傷。對於漂亮的URL來說太長了。 – yfeldblum 2009-10-21 04:24:42

+0

如果從int到Guid的轉換的唯一好處是一個開發人員可以單元測試整個生產系統的一部分。那麼是的,我認爲這是過度殺傷 – 2009-10-21 04:38:02

3

有幾個可能的角落,你可能挖到自己可能最終導致你問的問題。

  1. 也許你擔心重複使用主鍵和覆蓋或不正確地將數據加載中已有的數據庫(比如,如果你反對,而不是一個乾淨的測試數據庫開發數據庫測試)。在這種情況下,我建議你設置你的單元測試,使用普通應用程序在乾淨,專用的測試數據庫中測試的任何順序創建記錄的PK。

  2. 也許你擔心你的代碼與PK之外的效果超出簡單的1,2,3。請放心,這不是通常在直接應用程序中測試的東西,因爲大部分應用程序都不在應用程序的關注範圍之內:從一個序列中生成一個數字是DB供應商的問題,跟蹤內存中的數字是運行時/虛擬機的問題。

  3. 也許你只是想知道什麼是這種事情的最佳做法。我建議你在執行測試用例之前插入記錄,並使用應用程序本身將用於插入記錄的相同工具建立數據庫;大概你的應用程序代碼將依賴數據庫公開的PK序列號,如果是這樣的話。最後,在執行完測試用例之後,測試應該回滾他們對數據庫所做的任何更改,以確保多次執行測試爲idempotent。這是我描述名爲test fixtures的設計模式的抱歉嘗試。

0

數據庫單元測試的基本問題是主鍵不能被重用。相反,即使您使用原始密鑰刪除記錄,每次創建新記錄時,數據庫都會創建一個新密鑰。

有兩種基本的方法來處理這個:

  1. 閱讀生成的主鍵,從數據庫,並在測試中使用它,或者
  2. 使用的數據庫的新副本每次測試。

您可以將每個測試放入事務中,並在測試完成時將事務回滾,但回滾事務並不總是適用於主鍵;數據庫引擎仍然不會重用曾經生成過的密鑰(無論在SQL Server中)。

0

當通過另一段代碼對數據庫執行測試時,它不再是單元測試。它被稱爲「integration test」,因爲您正在測試不同代碼段的交互以及它們如何「集成」在一起。並不是說它真的很重要,但它很有趣。

當你進行測試時,應會發生以下情況:

  1. 開始一個數據庫事務
  2. 插入已知的(可能是假的)測試項目/實體
  3. 調用(唯一一個)功能進行測試
  4. 測試結果
  5. 回滾事務

這些事情應該發生在每一個測試中。使用NUnit,你可以在第1步和第5步中只寫一個基類,然後從每個測試類中繼承。 NUnit將在基類中執行Setup和Teardown裝飾方法。

在步驟2中,如果您使用的是SQL,則必須編寫查詢,以便將PK數字返回給您的測試代碼。

INSERT INTO Person(FirstName, LastName) 
VALUES ('Fred', 'Flintstone'); 
SELECT SCOPE_IDENTITY(); --SQL Server example, other db vendors vary on this. 

然後你就可以做到這一點

INSERT INTO Person(FirstName, LastName, SpouseId) 
VALUES('Wilma', 'Flintstone', @husbandId); 
SET @wifeId = SCOPE_IDENTITY(); 

UPDATE Person SET SpouseId = @wifeId 
WHERE Person.Id = @husbandId; 
SELECT @wifeId; 

或其他任何你需要的。

在步驟4中,如果使用SQL,則必須重新選擇數據並測試返回的值。

如果你足夠幸運能夠像(N)Hibernate(或其他)一樣使用像樣的ORM,步驟2和步驟4就不那麼複雜了。

+0

我不需要測試數據庫。我知道那作品 – 2009-10-21 21:11:26