2010-10-01 384 views
20

之間你怎麼做單元測試時,你有單元測試測試

  • 一些通用單元測試
  • 更復雜的測試檢查邊情況下,根據一般的人

舉個例子,想象一下測試一個CSV閱讀器(我只是做了一個演示的符號),

def test_readCsv(): ... 

@dependsOn(test_readCsv) 
def test_readCsv_duplicateColumnName(): ... 

@dependsOn(test_readCsv) 
def test_readCsv_unicodeColumnName(): ... 

我希望子測試只有在父測試成功時才能運行。這背後的原因是運行這些測試需要時間。許多故障報告迴歸到單一原因也無法提供信息。當然,我可以將所有邊緣案例都歸入主要測試,但是我想知道是否有更加結構化的方式來做到這一點。

我發現這些相關但不同的問題,

UPDATE:

我發現TestNG它具有很大的內置支持測試依賴關係。您可以編寫測試這樣,

@Test{dependsOnMethods = ("test_readCsv")) 
public void test_readCsv_duplicateColumnName() { 
    ... 
} 

回答

10

個人的東西,我就不會擔心單元測試之間創建依賴關係。這聽起來像是對我來說有點代碼味道。幾點:

  • 如果一個測試失敗,讓其他人不能及時瞭解不良代碼更改的問題規模。
  • 測試失敗應該是一個例外而不是標準,那麼爲什麼在絕大多數時候浪費精力和創建依賴關係(希望是!)沒有任何好處?如果失敗經常發生,您的問題不是單元測試依賴性,而是頻繁的測試失敗。
  • 單元測試應該運行得非常快。如果他們運行緩慢,那麼集中精力提高這些測試的速度,而不是防止後續的失敗。通過更多地解耦你的代碼並使用依賴注入或嘲弄來做到這一點。
+20

是的,但是:如果你有一件事情失敗並導致級聯失敗,你不能保證以正確的順序得到失敗消息來解決它們(尤其是如果你做任何測試的自動發現)。例如,我們有一組單元測試,用於檢查Web環境是否正確設置,其中(對其他用戶來說)對於新員工來說很方便。如果缺少文件X並且該文件在3個位置符號鏈接,則首先要修復丟失的文件。這對新手來說可能並不明顯,因此你會減少測試套件的用處。 – 2012-06-28 18:50:07

+0

有些情況下,測試之間需要依賴*。例如:測試登錄到外部服務器的API包裝器。該登錄會話需要在測試之間共享。 – 2017-11-06 19:17:58

2

我不知道你指的是什麼語言(只要你不具體提及它在你的問題),但這樣的事情PHPUnit的有一個@depends標記,只有在依賴測試已經通過的情況下才會運行測試。

取決於你用什麼語言或單元測試也可能有類似的可選

+0

示例代碼是python;) – naught101 2015-01-20 01:44:14

0

根據最佳實踐和單元測試原則,單元測試不應該依賴於其他測試。

每個測試用例都應檢查具體的隔離行爲。

然後,如果某個測試用例失敗,您將確切知道我們的代碼出了什麼問題。

+3

我和OP有同樣的問題。我有一個測試構造函數的測試。另一個測試在課堂上測試方法。顯然,如果構造函數失敗,那麼這兩個測試都會失敗,從而隱藏了我的代碼出了什麼問題。構造函數測試應該失敗,方法測試應該跳過。 – Oddthinking 2012-03-28 01:22:52

+0

這忽略了問題的關鍵。第二個測試可以獨立於第一個測試運行,並檢查具體的孤立行爲。但是,如果第一次測試失敗,則第二次測試將保證失敗,因此沒有意義。 – Oddthinking 2014-08-02 02:53:29

5

長鼻的Python版本TestNG(這是一個Java庫)。

參見packages.python.org/proboscis/

它支持的依賴關係,例如

@test(depends_on=[test_readCsv]) 
public void test_readCsv_duplicateColumnName() { 
    ... 
} 
+0

不確定是否錯過了某些東西,但我找不到如何使用長鼻支持setup_class()和setup()。它似乎有'@ before_class',但不是'@ before'。 – Zitrax 2015-06-09 11:48:43

2

我已經實現爲Nose(Python)的一個插件,其增加了對測試的依賴關係和測試優先級的支持。

正如在其他答案/評論中提到的,這通常是一個糟糕的主意,但是可能會有例外,您希望這樣做(在我的情況下,它是集成測試的性能 - 進入一個巨大的開銷可測試狀態,分鐘與小時)。

您可以在這裏找到它:nosedep

一個最小的例子是:

def test_a: 
    pass 

@depends(before=test_a) 
def test_b: 
    pass 

爲了確保test_b總是test_a之前運行。