2010-02-03 67 views
6

我需要爲某些python類創建單元測試。我有一個輸入數據庫和預期結果數據庫,應該由UUT生成這些輸入數據。如何編寫一個單元測試,其中每個測試用例有不同的輸入但是相同?

這裏是我想要做的僞代碼:這個使用單元測試包或者是有一些更好的測試包,爲此

for i=1 to NUM_TEST_CASES: 
    Load input for test case i 
    execute UUT on the input and save output of run 
    Load expected result for test case i 
    Compare output of run with the expected result 

我能實現嗎?

+0

爲了澄清你的問題,你的意思是像PHPUnit中的數據提供者? http://www.phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers – majelbstoat 2010-02-04 04:30:32

回答

4

你描述測試的方式對單元測試來說是一個奇怪的匹配。單元測試通常不會 - 加載測試數據或來自外部文件的其餘結果。一般來說,它只是在單元測試中進行硬編碼。

這並不是說你的計劃不會奏效。這只是說它是非典型的。

你有兩種選擇。

  1. (我們做什麼)。編寫一個腳本,它執行「爲測試用例i加載輸入」和「爲測試用例i加載預期結果」。使用它來生成所需的單元測試代碼。 (我們使用Jinja2模板從源文件編寫Python代碼。)

    然後刪除源文件。是的,刪除它們。他們只會迷惑你。

    你剩下的是「典型」形式的正確單元測試文件,包含測試用例和預期結果的靜態數據。

  2. 編寫您的setUp方法來執行「爲測試用例i加載輸入」和「爲測試用例i加載預期結果」。編寫你的test方法來鍛鍊UUT。

它可能看起來像這樣。

class OurTest(unittest.TestCase): 
    def setUp(self): 
     self.load_data() 
     self.load_results() 
     self.uut = ... UUT ... 
    def runTest(self): 
     ... exercise UUT with source data ... 
     ... check results, using self.assertXXX methods ... 

想要運行這麼多次嗎?一種方式來做這樣的事情。

class Test1(OurTest): 
    source_file = 'this' 
    result_file = 'that' 

class Test2(OutTest): 
    source_file= 'foo' 
    result_file= 'bar' 

這將允許unittest主程序找到並運行您的測試。

+0

謝謝。我想我會選擇1. Jinja2看起來很有趣。他們使用什麼許可證? – 2010-02-04 10:58:09

+1

@zr:「他們使用什麼許可證?」爲什麼要問我? PyPi頁面說:http://pypi.python.org/pypi/Jinja2。 – 2010-02-04 11:40:03

0

也許你可以使用doctest這個。瞭解你的投入和產出(並且能夠案件編號映射到一個函數名),你應該能夠產生一個文本文件是這樣的:

>>> from XXX import function_name1 
>>> function_name1(input1) 
output1 
>>> from XXX import function_name2 
>>> function_name2(input2) 
output2 
... 

,然後只用doctest.testfile('cases.txt')。這可能值得嘗試。

3

我們做這樣的事情才能運行實際上是什麼整合(迴歸)的unittest框架(實際上它們其中一個內部定製爲我們提供了巨大的好處,例如在羣集上並行運行試驗中測試機器等等 - 這種定製的巨大附加價值是我們如此熱衷於使用框架的原因)。

每個測試都在文件中表示(在該測試中使用的參數,然後是預期的結果)。我們integration_test讀取目錄下的所有這樣的文件,分析它們的每一個,然後調用:

def addtestmethod(testcase, uut, testname, parameters, expresults): 
    def testmethod(self): 
    results = uut(parameters) 
    self.assertEqual(expresults, results) 
    testmethod.__name__ = testname 
    setattr(testcase, testname, testmethod) 

我們先從一個空的測試用例類:

class IntegrationTest(unittest.TestCase): pass 

,然後調用addtestmethod(IntegrationTest, ...在一個循環我們正在讀取所有相關文件並解析它們以獲取測試名稱,參數和表達式。

最後,我們稱之爲內部專門的測試運行者,它負責繁重的工作(分佈在集羣中可用機器上的測試,收集結果等)。我們不想重塑那個富有附加價值的車輪,所以我們正在製作一個測試用例,儘量接近典型的「手工編碼」測試用例,以便「欺騙」測試跑步者,使其適合我們; - )。

除非您有具體的原因(好的測試者或類似人員)使用unittest的方法來進行(集成)測試,否則您可能會發現使用不同的方法可以讓您的生活更簡單。然而,這個方法非常可行,我們對它的結果非常滿意(主要包括大型集成/迴歸測試套件的快速運行!)。

+1

我發現自己使用「單元測試」來表示「我使用unittest或nUnit編寫的測試」,即使它們通常不是單元測試。 – 2010-02-04 04:44:45

0

您可能還想看看my answerthis question。我試圖做迴歸測試而不是單元測試,但單元測試框架對兩者都有好處。

在我的情況下,我有大約十幾個輸入文件,覆蓋了不同用例的公平傳播,並且我有大約六個測試函數,我想每個函數都要調用它們。

除了寫入72個不同的測試,其中大部分與輸入參數和結果數據相同之外,我創建了一個結果字典(其中鍵爲輸入參數,值爲每個函數的結果字典)測試)。然後我編寫了一個單獨的TestCase類來測試6個函數中的每一個,並通過多次將TestCase添加到測試套件來複制12個測試文件。

1

對我來說,好像pytest只是你需要的東西。

你可以parametrise tests這樣相同的測試運行多次你有輸入,它只需要一個裝飾器(沒有循環等)。

這裏有一個簡單的例子:

import pytest 
@pytest.mark.parametrize("test_input,expected", [ 
    ("3+5", 8), 
    ("2+4", 6), 
    ("6*9", 42), 
]) 
def test_eval(test_input, expected): 
    assert eval(test_input) == expected 

這裏parametrise有兩個參數 - 參數是一個字符串的名字,這些參數可迭代的值。

test_eval然後將被調用一次列表的每個元素。

相關問題