2008-12-07 22 views
6

這是我的previous question的後續行動。如何獲取鼻子來發現動態生成的測試用例?

在前面的問題中,我們探索了一些方法來實現對整個函數族進行基本相同的測試,以確保測試不會停在第一個失敗的函數上。

我的首選解決方案使用元類來動態地將測試插入unittest.TestCase。不幸的是,由於鼻子靜態掃描測​​試用例,所以鼻子不會選擇它。

如何獲得鼻子來發現並運行這樣的TestCase?有關TestCase的示例,請參閱here

+0

你試過我的解決方案嗎?它不是基於任何魔法,所產生的套件應該是可以發現的。 – muhuk 2008-12-07 15:50:19

回答

7

鼻子有這樣的東西「測試發電機」功能。你編寫一個生成器函數,生成你想運行它的每個「測試用例」函數以及它的參數。繼以前的例子,這可以檢查每個功能在一個單獨的測試:

import unittest 
import numpy 

from somewhere import the_functions 

def test_matrix_functions(): 
    for function in the_functions: 
     yield check_matrix_function, function 

def check_matrix_function(function) 
    matrix1 = numpy.ones((5,10)) 
    matrix2 = numpy.identity(5) 
    output = function(matrix1, matrix2) 
    assert matrix1.shape == output.shape, \ 
      "%s produces output of the wrong shape" % str(function) 
0

你可以嘗試生成測試用例類與類型()

class UnderTest_MixIn(object): 

    def f1(self, i): 
     return i + 1 

    def f2(self, i): 
     return i + 2 

SomeDynamicTestcase = type(
    "SomeDynamicTestcase", 
    (UnderTest_MixIn, unittest.TestCase), 
    {"even_more_dynamic":"attributes .."} 
) 

# or even: 

name = 'SomeDynamicTestcase' 
globals()[name] = type(
    name, 
    (UnderTest_MixIn, unittest.TestCase), 
    {"even_more_dynamic":"attributes .."} 
) 

當鼻子試圖導入test_module所以它應該工作這應該被創建。

這種方法的優點是可以動態創建多個測試組合。

2

鼻子不掃描測試靜態,這樣你就可以使用元類魔法使測試,鼻子找到。

難題在於標準元類技術不能正確設置func_name屬性,這是鼻子在檢查類中的方法是否爲測試時尋找的內容。

這是一個簡單的元類。它通過func dict來查看,併爲它找到的每個方法添加一個新方法,聲明它找到的方法有一個文檔字符串。這些新的合成方法被命名爲"test_%d" %i

import new 
from inspect import isfunction, getdoc 

class Meta(type): 
    def __new__(cls, name, bases, dct): 

     newdct = dct.copy() 
     for i, (k, v) in enumerate(filter(lambda e: isfunction(e[1]), dct.items())): 
      def m(self, func): 
       assert getdoc(func) is not None 

      fname = 'test_%d' % i 
      newdct[fname] = new.function(m.func_code, globals(), fname, 
       (v,), m.func_closure) 

     return super(Meta, cls).__new__(cls, 'Test_'+name, bases, newdct) 

現在,讓我們創建一個使用此元類

class Foo(object): 
    __metaclass__ = Meta 

    def greeter(self): 
     "sdf" 
     print 'Hello World' 

    def greeter_no_docstring(self): 
     pass 

在運行時,Foo實際上將被命名爲Test_Foo,將有greetergreeter_no_docstringtest_1test_2作爲其方法的新類。當我運行nosetests這個文件,這裏的輸出:

$ nosetests -v test.py 
test.Test_Foo.test_0 ... FAIL 
test.Test_Foo.test_1 ... ok 

====================================================================== 
FAIL: test.Test_Foo.test_0 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/nose/case.py", line 197, in runTest 
    self.test(*self.arg) 
    File "/Users/rmcgibbo/Desktop/test.py", line 10, in m 
    assert getdoc(func) is not None 
AssertionError 

---------------------------------------------------------------------- 
Ran 2 tests in 0.002s 

FAILED (failures=1) 

的是這元類是不是真的有用,但如果改用Meta不是一個合適的元類,但隨着越來越多的功能元類(即採取一個類作爲參數,並返回一個新的類,一個重命名,以便鼻子會發現它),那麼是有用的。我已經使用這種方法來自動測試文檔字符串是否符合Numpy標準,作爲鼻子測試套件的一部分。

此外,我有很多麻煩得到適當的封閉與新的工作。函數,這就是爲什麼此代碼使用m(self, func)其中func被設置爲默認參數。使用value以上的封閉會更自然,但這似乎不起作用。

相關問題