2013-12-11 61 views
3

我有以下測試類定義。它使用我通常不喜歡的exec代碼自編寫測試方法的pythonic方法

class FubarTest(unittest.TestCase): 
    lst = [(True, True), 
      (False, False)] 
    for t in lst: 
     function = """def test_{}_is_{}(self): 
     self.assertTrue({} is {}) 
     """.format(t[0], t[1], t[0], t[1]) 
     exec function 

當我運行它(通過py.test但這不應該的問題),我得到這個:

============================= test session starts ============================== 
platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /usr/bin/python 
plugins: capturelog, cov, twisted, xdist 

model/test/test_hframe5.py <- <string>:1: HFrame5Test.test_False_is_False PASSED 
model/test/test_hframe5.py <- <string>:1: HFrame5Test.test_True_is_True PASSED 
=========================== 2 passed in 0.49 seconds =========================== 

使得測試自動創建和有理智的名稱,以便如果事情失敗了,你知道通過方法的名稱失敗了。

顯然這是一個簡單的例子,我想要做什麼。我有很多測試,看起來像「做X,檢查Y是真的,Z是假的」,這可以很容易地用上面的方法編碼。我可以寫出三十種複製粘貼的方法,但這只是感覺不對 - 打破DRY。

是否有更符合pythonic的方式來編寫此代碼?

回答

1

你想參數化測試。例如,parameterizedtestcase

from parameterizedtestcase import ParameterizedTestCase 

class MyTests(ParameterizedTestCase): 
    @ParameterizedTestCase.parameterize(
     ("value", "expected"), 
     [ 
      (True, True), 
      (False, False), 
     ] 
    ) 
    def test_identical(self, value, expected): 
     self.assertTrue(value is expected) 

使用py.test's parametrization framework

import pytest 

@pytest.mark.parametrize(
    ("value", "expected"), 
    [ 
     (True, True), 
     (False, False), 
    ] 
) 
def test_identical(value, expected): 
    assert value is expected 
+0

有趣的是,這是基於[py.test的參數測試](http://pytest.org/latest/example/parametrize.html),因爲我已經使用了py.test,所以它很適合我。 – Sardathrion

+1

好啊,我也會給出一個最好的例子。我認爲這是一個很棒的測試框架。 – ecatmur

1

我通常會在更多的測試方面犯錯,而不是少測試,真的不管它做得如何。你可能沒事。

+0

[OF中Testivus路(http://www.artima.com/ weblogs/viewpost.jsp?thread = 203994)指出*有時,測試證明手段*。但是,如果我可以進行pythonic測試,並且遵循Python的[Zen of Python](http://www.python.org/dev/peps/pep-0020/)聲明* beautiful比醜陋*更好好多了。 – Sardathrion

1

你幾乎肯定不需要使用exec。只需使用'setattr'爲類添加合適的函數,並使用嵌套的作用域來綁定測試值。舉例來說,我認爲這應該工作:

class FubarTest(unittest.TestCase): 
    pass 

def createTest(cls, arg1, arg2): 
    def test(self): 
     self.assertTrue(arg1 is arg2) 
    testname = "test_{}_is_{}".format(arg1, arg2) 
    setattr(cls, testname, test) 

def createTests(): 
    lst = [(True, True), 
     (False, False)] 
    for a,b in lst: 
     createTest(FubarTest, a, b) 

createTests() 
+0

+1,如果只是爲了不使用'exec'的恐怖......^_〜 – Sardathrion

1

如果你使用的鼻子,你可以使用一個test generator

class FubarTest(object): 

    def check_is(self, a, b): 
     assert {} is {} 

    def test_is(self): 
     lst = [(True, True), (False, False)] 
     for a, b in lst: 
      self.check_is(a, b) 
+0

我不使用鼻子,但這是一個有用的答案。謝謝。 – Sardathrion

相關問題