簡體   English   中英

單元測試和主鍵

[英]Unit Testing & Primary Keys

我是單元測試的新手,並且認為自己可能陷入困境。

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

希望一個例子可以畫一些背景。 如果創建一個對象的多個實例(讓我們說人)。

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

我的代碼是創建Homer,他是Bart和Lisa的孩子。 他還有一個朋友Barney,Karl和Lenny。

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

主鍵是什么都沒有關系,只需要唯一即可。

有什么想法嗎???

編輯:

抱歉,我沒有說清楚。 我的項目設置為使用依賴注入 數據層是完全獨立的。 我的問題的重點是,什么是實用的?

您可能會陷入幾個角落,最終可能會導致您要問的問題。

  1. 也許您擔心重新使用主鍵,覆蓋或錯誤地加載數據庫中已有的數據(例如,如果要針對開發數據庫而不是干凈的測試數據庫進行測試)。 在這種情況下,我建議您設置單元測試,以使用正常應用程序將使用的順序創建其記錄的PK, 或者在干凈的專用測試數據庫中進行測試。

  2. 也許您擔心簡單的1,2,3之外的PK的代碼的有效性。 請放心,這不是在簡單的應用程序中通常會測試的東西,因為其中大多數都超出了您的應用程序的關注范圍:從序列生成數字是數據庫供應商的問題,在內存中跟蹤數字是運行時/ VM的問題。

  3. 也許您只是想了解這種事情的最佳實踐。 我建議您在執行測試用例之前,使用應用程序本身將用於插入記錄的相同工具,通過插入記錄來建立數據庫。 大概您的應用程序代碼將依賴於數據庫出售的PK序列號,如果是,請使用該序列號。 最后,在執行完測試用例之后,您的測試應回滾對數據庫所做的所有更改,以確保測試在多次執行中是冪等的 這是我遺憾的描述一種稱為測試夾具的設計模式的嘗試。

我有一個稱為“ Unique”的類,它產生唯一的對象(字符串,整數等)。 通過保留內部靜態計數器,確保每次測試的唯一性。 每個生成的密鑰都會增加該計數器的值,並以某種方式包含在密鑰中。

所以當我設置測試時

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

我喜歡這一點,因為它表明該值對於該測試並不重要,而僅僅是唯一性。

我有一個類似的類“ Some”,不能保證唯一性。 當我需要任意值進行測試時,可以使用它。 它對枚舉和實體對象很有用。

這些都不是線程安全的或類似的嚴格測試代碼。

考慮使用GUID。 它們在時空上是唯一的,這意味着即使兩台不同的計算機在同一時間准確地生成了它們,它們也將是不同的。 換句話說,它們保證是唯一的。 隨機數永遠都不好,有很大的碰撞風險。

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

Guid.NewGuid();

假設這是C#。

編輯:

另一件事,如果您只想生成大量測試數據而不必手動編寫代碼或編寫大量的for循環,請查看NBuilder 入門可能有點困難(帶有方法鏈接的流式方法並不總是為了提高可讀性而已),但這是創建大量測試數據的好方法。

為什么要使用隨機數? 密鑰的數值重要嗎? 我只是在數據庫中使用一個序列,然后調用nextval。

數據庫單元測試的本質問題是主鍵不會被重用。 而是,即使您使用原始鍵刪除了記錄,數據庫也會在每次創建新記錄時創建一個新鍵。

有兩種基本方法可以解決此問題:

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

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

當測試通過另一段代碼對數據庫執行時,它將不再是單元測試。 之所以稱為“ 集成測試 ”,是因為您正在測試不同代碼段之間的交互以及它們如何“集成”在一起。 並不是說它真的很重要,而是知道它的樂趣。

執行測試時,應發生以下情況:

  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的復雜程度將降低。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM