2012-11-28 79 views
9

this question類似,我希望鼻子可以並行運行測試(或所有測試)n次 - 但是不是用鼻子重複進行單個或多個測試

我在一個項目中有幾百個測試;有些是一些簡單的單元測試。其他的是集成測試,有一定程度的併發性。在調試測試時,我經常需要更加「打」測試;一個bash循環可以工作,但會產生很多混亂的輸出 - 沒有更好的單一「。」爲每個通過測試。有能力擊敗選定的測試進行一些試驗似乎是一個自然的事情,要求鼻子做,但我沒有發現它在文檔中的任何地方。

什麼是最簡單的方法讓鼻子做到這一點(除了bash循環)?

+0

如果你說明你爲什麼要這樣做,這可能會有所幫助。另外,'n'是否有所不同?如果是這樣,你想如何指定它? (例如,在運行測試時在命令行中)爲什麼沒有Bash?這對於這項工作似乎是完美的。 –

+0

我擴展了這個問題的基本原理。 – JohnJ

回答

14

您可以write a nose test as a generator和鼻子會再運行每個功能 產生:

def check_something(arg): 
    # some test ... 

def test_something(): 
    for arg in some_sequence: 
     yield (check_something, arg) 

使用nose-testconfig,你可以讓測試運行的數量的命令行參數:

from testconfig import config 

# ... 

def test_something(): 
    for n in range(int(config.get("runs", 1))): 
     yield (check_something, arg) 

你從命令行調用例如

$ nosetests --tc=runs:5 

...多於一次運行。

或者(但也使用鼻testconfig),你可以寫一個裝飾:

from functools import wraps 
from testconfig import config 

def multi(fn): 
    @wraps(fn) 
    def wrapper(): 
     for n in range(int(config.get("runs", 1))): 
      fn() 
    return wrapper 

@multi 
def test_something(): 
    # some test ... 

然後,如果你想你的測試分爲不同的組,每組爲自己的命令行參數運行次數:

from functools import wraps 
from testconfig import config 

def multi(cmd_line_arg): 
    def wrap(fn): 
     @wraps(fn) 
     def wrapper(): 
      for n in range(int(config.get(cmd_line_arg, 1))): 
       fn() 
     return wrapper 
    return wrap 

@multi("foo") 
def test_something(): 
    # some test ... 

@multi("bar") 
def test_something_else(): 
    # some test ... 

,你可以這樣調用:

$ nosetests --tc=foo:3 --tc=bar:7 
+0

您實際上並未在您的示例中使用換行。需要嗎? – JohnJ

+0

那麼斑點:-)是的,因爲否則裝飾的功能將沒有正確的名稱和鼻子不會找到它。修正(連同其他一些小錯誤)。 –

+0

太棒了! upvoted的答案 - 雖然它不是我想要的,因爲我不得不裝飾每一個O(200)測試。開始懷疑我是否應該咬緊牙關,看看是否可以爲它寫一個鼻子插件。再次感謝。 – JohnJ

2

的一種方法是在測試本身:

更改此:

class MyTest(unittest.TestCase): 

    def test_once(self): 
     ... 

要這樣:

class MyTest(unittest.TestCase): 

    def assert_once(self): 
     ... 

    def test_many(self): 
     for _ in range(5): 
      self.assert_once() 
+2

當然,這是微不足道的 - 我通常很高興每次運行一次測試,但如果我懷疑單個測試(或測試類)偶爾會失敗,那麼讓測試框架給我選項。 – JohnJ

0

有永遠不應該成爲理由來運行測試一次以上。測試是確定性的(即給定相同的代碼庫狀態,它們始終產生相同的結果)非常重要。如果情況並非如此,那麼不必多次運行測試,您應該重新設計測試和/或代碼,以便他們。

例如,測試失敗間歇性的一個原因是測試與被測代碼(CUT)之間的競爭條件。在這種情況下,一個天真的迴應是在測試中加入一個大的'伏都休眠',以便在測試開始斷言之前'確保'CUT完成。

雖然這很容易出錯,因爲如果你的CUT由於某種原因(硬件不足,加載盒子,繁忙的數據庫等)速度很慢,那麼它會偶爾失敗。在這種情況下,更好的解決方案是讓您的測試等待事件,而不是睡覺。

事件可能是您選擇的任何事情。有時,您可以使用的事件已經被生成(例如,Javascript DOM事件,Selenium測試可以利用的'pageRendered'事件類型)。其他時候,您可能需要向CUT添加代碼, (或許您的架構涉及其他對此類事件感興趣的組件)

通常,您需要重新編寫測試,以便它會嘗試檢測您的CUT是否已完成執行(例如輸出文件是否存在?),如果沒有,睡覺50ms,然後再次嘗試。最終它會超時和失敗,但只能在很長一段時間後執行此操作(例如,CUT的預期執行時間的100倍)。

另一種方法是使用'洋蔥/六角形/端口'適配器的原則,堅持你的業務邏輯應該沒有任何外部依賴。這意味着您的業務邏輯可以使用普通的亞毫秒單元測試進行測試,這些測試從不接觸網絡或文件系統。完成此操作後,您需要的端到端系統測試遠遠更少,因爲它們現在僅用作集成測試,並且不需要嘗試操縱通過用戶界面的業務邏輯的每個細節和邊緣情況。這種方法在其他方面也會帶來很大的好處,例如改進的CUT設計(減少組件間的依賴關係),測試更容易編寫,運行整個測試套件的時間大大縮短。

使用類似上述的方法可以完全消除不可靠的測試問題,我建議這樣做,不僅可以改進測試,還可以改善代碼庫和設計能力。

+0

Downvote,因爲OP沒有問*他是否應該多次運行測試,他問*如何做*。 –

+0

沒錯,但有時候最好的答案就是說「嘗試一種不同的方法」,而不是幫助他們走上錯誤的道路。我不確定當地的規範是什麼,但我認爲downvote是苛刻的:這個答案可能對考慮類似問題的其他人有用。 –

+3

肯定!但是,這就是「添加評論」按鈕的用途。或者,由於您似乎也回答了問題,爲什麼不在那裏添加警告? –

2

您必須編寫一個腳本來執行此操作,但是您可以在命令行X次重複測試名稱。

nosetests testname testname testname testname testname testname testname 

1

解決方案最後我用的就是創建sh腳本run_test.sh:

var=0 
while $1; do 
    ((var++)) 
    echo "*** RETRY $var" 
done 

用法:

./run_test.sh "nosetests TestName" 

它無限運行試驗,但先停止上錯誤。

相關問題