這是我的previous question的後續行動。如何獲取鼻子來發現動態生成的測試用例?
在前面的問題中,我們探索了一些方法來實現對整個函數族進行基本相同的測試,以確保測試不會停在第一個失敗的函數上。
我的首選解決方案使用元類來動態地將測試插入unittest.TestCase。不幸的是,由於鼻子靜態掃描測試用例,所以鼻子不會選擇它。
如何獲得鼻子來發現並運行這樣的TestCase?有關TestCase的示例,請參閱here。
這是我的previous question的後續行動。如何獲取鼻子來發現動態生成的測試用例?
在前面的問題中,我們探索了一些方法來實現對整個函數族進行基本相同的測試,以確保測試不會停在第一個失敗的函數上。
我的首選解決方案使用元類來動態地將測試插入unittest.TestCase。不幸的是,由於鼻子靜態掃描測試用例,所以鼻子不會選擇它。
如何獲得鼻子來發現並運行這樣的TestCase?有關TestCase的示例,請參閱here。
鼻子有這樣的東西「測試發電機」功能。你編寫一個生成器函數,生成你想運行它的每個「測試用例」函數以及它的參數。繼以前的例子,這可以檢查每個功能在一個單獨的測試:
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)
你可以嘗試生成測試用例類與類型()
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所以它應該工作這應該被創建。
這種方法的優點是可以動態創建多個測試組合。
鼻子不掃描測試靜態,這樣你就可以使用元類魔法使測試,鼻子找到。
難題在於標準元類技術不能正確設置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
,將有greeter
,greeter_no_docstring
,test_1
和test_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
以上的封閉會更自然,但這似乎不起作用。
你試過我的解決方案嗎?它不是基於任何魔法,所產生的套件應該是可以發現的。 – muhuk 2008-12-07 15:50:19