動的に生成されたテストケースを発見するにはどうすればいいですか?
-
19-08-2019 - |
解決
Noseには<!> quot; test generator <!> quot;があります。このようなもののための機能。各<!> quot;テストケース<!> quotを生成するジェネレーター関数を作成します。実行する関数とその引数。前の例に続いて、個別のテストで各関数を確認できます。
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)
他のヒント
Noseはテストを静的にスキャンしないため、メタクラスマジックを使用して、Noseが検出するテストを作成できます。
難しいのは、標準のメタクラス手法ではfunc_name属性が正しく設定されないことです。これは、クラスのメソッドがテストであるかどうかをチェックするときにNoseが探すものです。
これは単純なメタクラスです。 func dictを調べて、見つかったすべてのメソッドに新しいメソッドを追加し、見つかったメソッドにdocstringがあることをアサートします。これらの新しい合成メソッドには、"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
を適切なメタクラスとしてではなく、より機能的なメタクラスとして使用する場合(つまり、クラスを引数として、新しいクラスを返します)鼻がそれを見つけるように名前が変更されています)、それは便利です 。このアプローチを使用して、docstringsがノーズテストスイートの一部としてNumpy標準に準拠していることを自動的にテストしました。
また、new.functionで適切なクロージャを動作させるのに苦労しました。そのため、このコードではm(self, func)
を使用します。ここで、func
はデフォルトの引数になります。 value
でクロージャを使用する方が自然ですが、それはうまくいかないようです。
type()を使用してテストケースクラスを生成しようとすることができます
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 .."}
)
これは、noseがtest_moduleをインポートしようとするときに作成されるため、動作するはずです。
このアプローチの利点は、テストの多くの組み合わせを動的に作成できることです。