現在、共通のテストセットを共有するいくつかのユニットテストがあります。以下に例を示します。
import unittest
class BaseTest(unittest.TestCase):
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(BaseTest):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(BaseTest):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __== '__main__':
unittest.main()
上記の出力は次のとおりです。
Calling BaseTest:testCommon
.Calling BaseTest:testCommon
.Calling SubTest1:testSub1
.Calling BaseTest:testCommon
.Calling SubTest2:testSub2
.
----------------------------------------------------------------------
Ran 5 tests in 0.000s
OK
最初のtestCommon
が呼び出されないように上記を書き換える方法はありますか?
編集:上記の5つのテストを実行する代わりに、SubTest1から2つ、SubTest2から2つのテストを4つだけ実行するようにします。 Python unittestは独自に元のBaseTestを実行しているため、それを防ぐメカニズムが必要です。
多重継承を使用して、共通のテストを含むクラスがTestCaseを継承しないようにします。
import unittest
class CommonTests(object):
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(unittest.TestCase, CommonTests):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(unittest.TestCase, CommonTests):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __== '__main__':
unittest.main()
多重継承を使用しないでください。噛み付きます 後で 。
代わりに、基本クラスを個別のモジュールに移動するか、空のクラスでラップすることができます。
import unittest
class BaseTestCases:
class BaseTest(unittest.TestCase):
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(BaseTestCases.BaseTest):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(BaseTestCases.BaseTest):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __== '__main__':
unittest.main()
出力:
Calling BaseTest:testCommon
.Calling SubTest1:testSub1
.Calling BaseTest:testCommon
.Calling SubTest2:testSub2
.
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
単一のコマンドでこの問題を解決できます。
del(BaseTest)
したがって、コードは次のようになります。
import unittest
class BaseTest(unittest.TestCase):
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(BaseTest):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(BaseTest):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
del(BaseTest)
if __== '__main__':
unittest.main()
Matthew Marshallの答えは素晴らしいですが、テストケースごとに2つのクラスから継承する必要があり、エラーが発生しやすくなります。代わりに、これを使用します(python> = 2.7):
class BaseTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
if cls is BaseTest:
raise unittest.SkipTest("Skip BaseTest tests, it's a base class")
super(BaseTest, cls).setUpClass()
何を達成しようとしていますか?共通のテストコード(アサーション、テンプレートテストなど)がある場合は、test
が前に付いていないメソッドに配置して、unittest
がロードしないようにします。
import unittest
class CommonTests(unittest.TestCase):
def common_assertion(self, foo, bar, baz):
# whatever common code
self.assertEqual(foo(bar), baz)
class BaseTest(CommonTests):
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(CommonTests):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(CommonTests):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __== '__main__':
unittest.main()
マシューの答えは、私がまだ2.5を使用しているので使用する必要があるものです。ただし、2.7以降では、スキップするテストメソッドで@ unittest.skip()デコレータを使用できます。
http://docs.python.org/library/unittest.html#skipping-tests-and-expected-failures
基本型を確認するには、独自のスキップデコレータを実装する必要があります。これまでこの機能を使用したことはありませんが、頭の中で、BaseTestをmarkerタイプとして使用して、スキップを調整できます。
def skipBaseTest(obj):
if type(obj) is BaseTest:
return unittest.skip("BaseTest tests skipped")
return lambda func: func
別のオプションは実行しないことです
unittest.main()
その代わりに使用できます
suite = unittest.TestLoader().loadTestsFromTestCase(TestClass)
unittest.TextTestRunner(verbosity=2).run(suite)
したがって、クラスTestClass
のテストのみを実行します。
これを解決するために私が考えた方法は、基本クラスが使用されている場合、テストメソッドを非表示にすることです。この方法では、テストがスキップされないため、多くのテストレポートツールでテスト結果が黄色ではなく緑色になります。
Mixinメソッドと比較して、PyCharmのようなideは、単体テストメソッドが基本クラスにないことを文句を言いません。
基本クラスがこのクラスを継承する場合、setUpClass
およびtearDownClass
メソッドをオーバーライドする必要があります。
class BaseTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._test_methods = []
if cls is BaseTest:
for name in dir(cls):
if name.startswith('test') and callable(getattr(cls, name)):
cls._test_methods.append((name, getattr(cls, name)))
setattr(cls, name, lambda self: None)
@classmethod
def tearDownClass(cls):
if cls is BaseTest:
for name, method in cls._test_methods:
setattr(cls, name, method)
cls._test_methods = []
BaseTestクラスに__test_ = False
を追加できますが、追加する場合は、テストを実行できるように派生クラスに__test__ = True
を追加する必要があることに注意してください。
import unittest
class BaseTest(unittest.TestCase):
__test__ = False
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(BaseTest):
__test__ = True
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(BaseTest):
__test__ = True
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __== '__main__':
unittest.main()
@Vladim Pとほぼ同じように作成しました(- https://stackoverflow.com/a/25695512/2451329 )が、少し変更しました:
import unittest2
from some_module import func1, func2
def make_base_class(func):
class Base(unittest2.TestCase):
def test_common1(self):
print("in test_common1")
self.assertTrue(func())
def test_common2(self):
print("in test_common1")
self.assertFalse(func(42))
return Base
class A(make_base_class(func1)):
pass
class B(make_base_class(func2)):
def test_func2_with_no_arg_return_bar(self):
self.assertEqual("bar", func2())
そしてそこに行きます。
これは一種の古いスレッドですが、今日この問題に遭遇し、それに対する私自身のハックを考えました。基本クラスを介してアクセスされると、関数の値をNoneにするデコレーターを使用します。ベースクラスにテストがない場合は実行されないため、セットアップとセットアップクラスについて心配する必要はありません。
import types
import unittest
class FunctionValueOverride(object):
def __init__(self, cls, default, override=None):
self.cls = cls
self.default = default
self.override = override
def __get__(self, obj, klass):
if klass == self.cls:
return self.override
else:
if obj:
return types.MethodType(self.default, obj)
else:
return self.default
def fixture(cls):
for t in vars(cls):
if not callable(getattr(cls, t)) or t[:4] != "test":
continue
setattr(cls, t, FunctionValueOverride(cls, getattr(cls, t)))
return cls
@fixture
class BaseTest(unittest.TestCase):
def testCommon(self):
print('Calling BaseTest:testCommon')
value = 5
self.assertEqual(value, 5)
class SubTest1(BaseTest):
def testSub1(self):
print('Calling SubTest1:testSub1')
sub = 3
self.assertEqual(sub, 3)
class SubTest2(BaseTest):
def testSub2(self):
print('Calling SubTest2:testSub2')
sub = 4
self.assertEqual(sub, 4)
if __== '__main__':
unittest.main()
TestCommonメソッドの名前を別のものに変更するだけです。 Unittestは(通常) 'test'を含まないものはすべてスキップします。
早くて簡単
import unittest
class BaseTest(unittest.TestCase):
def methodCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(BaseTest):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(BaseTest):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __== '__main__':
unittest.main()`
Python 3.2の時点で、モジュールに test_loader 関数を追加して、テスト検出メカニズムによって検出されるテスト(存在する場合)を制御できます。
たとえば、次のコードは元のポスターのSubTest1
およびSubTest2
テストケースのみを読み込み、Base
を無視します。
def load_tests(loader, standard_tests, pattern):
suite = TestSuite()
suite.addTests([SubTest1, SubTest2])
return suite
standard_tests
(デフォルトのローダーが検出したテストを含むTestSuite
)を反復処理し、代わりにBase
を除くすべてをsuite
にコピーする必要がありますが、 TestSuite.__iter__
のネストされた性質により、それはさらに複雑になります。