2012-04-23 66 views
8

假設你有一個網站,它使用一個函數從數據庫中檢索數據並返回結果以顯示/解析/等...如何爲依賴動態數據的函數編寫單元測試?

由於從數據庫檢索到的數據是動態的,潛在地改變一天中的每一秒,你如何正確編寫這個函數的單元測試?

讓我們假設該函數應該返回一個結果數組。很顯然,單元測試可以測試數組是否返回。但是當由於錯誤地寫入MySQL查詢而導致數組內容不正確時會發生什麼?數組的大小可能爲零,或者數組的內容可能不正確。由於它依賴於不斷變化的數據,單元測試如何知道什麼是正確的?哪些不是?是否需要從單元測試本身調用數據庫,以便將它與之進行比較?

如何正確地爲依賴動態數據的函數編寫單元測試?

+0

這可能很有趣:http://blog.schauderhaft.de/2011/03/13/testing-databases-with-junit-and -hibernate-part-1-one-to-rule-them/ – 2012-04-23 20:58:58

回答

7

單元測試,在他們的理想形式中,應該只測試一件事情。在這種情況下,你要測試兩件事情:

  1. 你的函數的邏輯
  2. 數據庫檢索

所以我建議以下重構:

  1. 移動數據庫檢索邏輯分成單獨的功能
  2. 有你想測試的功能調用其他功能
  3. 模擬出返回數據的函數,以便您可以單元測試您的應用程序的邏輯
  4. 如果有意義(如果您只是依賴另一個庫來執行此操作,那麼希望該庫已經有測試),爲動態檢索函數編寫一個單元測試,其中不能測試特定的內容,但可以測試返回數據的結構和合理性(例如它具有所有的字段設置,並且是現在5秒內的時間)。

此外,通常在測試環境中運行單元測試是一個好主意,您可以完全控制數據庫中存儲的內容。您不希望針對生產數據運行這些數據。

+0

好點。所以你說我們應該只測試數據檢索功能的邏輯,而不是檢索的數據是否正確?另外,在我們的開發環境中,我們通常會對我們的實時數據庫 - >開發數據庫進行單向同步,以便我們處理最近的數據。無論如何,數據仍然是動態的。謝謝。 – 2012-04-23 22:10:44

+0

在單元級別上,我傾向於測試我寫入數據庫的邏輯是否正確,以及我對讀取操作的邏輯。我不需要對數據庫進行單元測試,除非我使用一些自定義的ORM。然後,我通常會編寫功能或集成測試,以顯示我的數據是我期望的數據。針對沒有被測試以外的其他任何內容更新的數據庫執行這些操作。使用動態數據模擬真實世界的場景對於集成(和性能)測試來說很好,但對系統的信心應該來自其他方面。 – 2012-04-24 04:54:02

+0

你如何模擬一個功能? – 2016-10-27 03:04:20

0

你不能,真的。您需要有保證的靜態數據集才能創建可靠的單元測試。也許數據庫快照可能適合你。

動態數據可以以其他方式是有用的,例如以執行迴歸測試...

0

大多數試驗集中於所涉及的東西等獲取數據的邏輯路徑。不在數據本身的有效性上。數據的有效性只有在您的應用程序以某種方式計算或聚合它時纔有意義,在這種情況下,您應該能夠控制輸入並驗證結果是否正確。

也就是說,有時候您確實想要使用您的應用程序用於驗證退貨的相同數據庫。例如,如果您正在測試返回過濾數據集的函數,則您的單元測試可以執行相同的查詢,然後對每個記錄主鍵進行逐行比較,並驗證函數是否返回了同樣的數據集合,你期待。

我不知道這是否是您的具體問題,但在單元測試中敲擊數據庫執行斷言沒有任何問題,相反。至少我一直這樣做,沒有人試圖讓我被捕:)

0

忽略你正在談論數據庫的事實,我認爲你可能正在尋找你的單元測試來涵蓋每一個事件,因爲這可能導致一系列收益遞減。如果我是你,我會覆蓋一條標準路徑,然後覆蓋一些邊緣案例。事實是,你不能務實地測試一切。

下面是一些進一步閱讀

http://37signals.com/svn/posts/3159-testing-like-the-tsa
How deep are your unit tests?
http://johnnosnose.blogspot.co.uk/2012/04/re-over-testing.html
http://martinfowler.com/bliki/TestCoverage.html

看着你specifc分貝的相關問題,以測試這個功能,你可能需要創建一個seam預poulate數據所以你可以覆蓋這些情況。

+0

heh根據我的經驗,大多數錯誤正好在難以測試的區域蔓延 - 因此看起來這些是唯一真正從測試框架中進行時間投資中受益的領域。管理人員看到這一點,我確信並且認爲,「實際上'x','y'和'z'基本上由幾乎不可測試的特性定義時,我們只需要更多的x,y z的單元測試。出於這些原因,我認爲單元測試幾乎比最僵化,非敏捷的基於UML的OOP實踐更靈活。作爲一個每小時工作的獨立開發者,這對於一顆銀彈來說確實是一份工作。 – 2015-06-03 14:51:13

1

如果你的函數做了一些有趣的事情,除了將數據從數據庫中提取出來之外,你應該將檢索提取到一個不同的函數中,並對其進行模擬,以便測試其餘的部分。

這仍然會讓您執行測試數據庫訪問的任務。你不能真的爲此做一個單元測試,因爲按定義它不會訪問任何數據庫,你可以測試它是否發送你認爲它應該的sql語句,但是如果sql語句實際工作則不會。

所以你需要一個數據庫

你有不同的optiones:

1)創建這樣的測試不得到由測試改變一個固定的數據庫。

專業:概念上容易 騙局:難以維護。測試變得相互依賴,因爲它們依賴於相同的數據。沒有辦法測試更新,插入或刪除的東西(更不用說DDL)

2)在測試期間創建數據庫。現在你有兩個問題:爲測試設置數據庫並填充數據。

設置:

1)有一個數據庫服務器上運行,與erveryone用戶/模式/數據庫誰需要運行測試(至少開發者+ CI服務器)。架構可以使用諸如hibernate之類的東西或用於部署的腳本來創建。

工程很好,但讓老派的DBA瘋狂。應用程序不能依賴於模式名稱。當您有多個應用程序使用的架構時,您也會遇到問題。這種設置相當緩慢。它可以幫助放入快速光盤。像RAM光盤

2)有一個內存數據庫。易於從代碼開始並且快速。但在大多數情況下,它的行爲與生產數據庫相同。如果你使用某些試圖掩蓋差異的東西,那麼這個問題就不那麼重要了。我經常在第一階段使用內存數據庫,第二階段使用內存數據庫。

加載測試數據

1)人們告訴我使用dbunit。我不認爲它看起來很多XML,並且在列或約束更改時很難維護。

2)我更喜歡普通的應用程序代碼。 (Java + Hibernate),但是在生產環境中將數據寫入數據庫的代碼在很多情況下適用於爲測試編寫測試數據。它有助於有一個特殊的API隱藏滿足所有外鍵和東西的細節:http://blog.schauderhaft.de/2011/03/13/testing-databases-with-junit-and-hibernate-part-1-one-to-rule-them/

0

我會在測試本身中構建數據。這樣,您甚至可以針對不斷變化的數據測試複雜的場景。關鍵是您可以通過專門的測試數據庫來控制數據更改步驟1:將需要的數據插入僅由測試使用的數據庫中 步驟2:數據庫爲現在處於穩定的可預測狀態,因此您可以運行查詢並測試輸出