4

フレームワークのテストを作成すると、次のパターンに気付き始めます。

class SomeTestCase(unittest.TestCase):

    def test_feat_true(self):
        _test_feat(self, True)

    def test_feat_false(self):
        _test_feat(self, False)

    def _test_feat(self, arg):
        pass    # test logic goes here

test_feat_*そのため、メタクラスを使用して、これらのタイプのテストクラスのメソッドをプログラムで作成したいと思います。つまり、署名付きのプライベートメソッドごとに、署名付き_test_{featname}(self, arg)の2つのトップレベルの検出可能なメソッドとtest_{featname}_true(self)test_{featname}_false(self)作成する必要があります。

私は次のようなものを思いついた:

#!/usr/bin/env python

import unittest


class TestMaker(type):

    def __new__(cls, name, bases, attrs):
        callables = dict([
            (meth_name, meth) for (meth_name, meth) in attrs.items() if
            meth_name.startswith('_test')
        ])

        for meth_name, meth in callables.items():
            assert callable(meth)
            _, _, testname = meth_name.partition('_test')

            # inject methods: test{testname}_{[false,true]}(self)
            for suffix, arg in (('false', False), ('true', True)):
                testable_name = 'test{0}{1}'.format(testname, suffix)
                attrs[testable_name] = lambda self: meth(self, arg)

        return type.__new__(cls, name, bases, attrs)


class TestCase(unittest.TestCase):

    __metaclass__ = TestMaker

    def _test_this(self, arg):
        print 'this: ' + str(arg)

    def _test_that(self, arg):
        print 'that: ' + str(arg)


if __name__ == '__main__':
    unittest.main()

私は次のような出力を期待しています:

this: False
this: True
that: False
that: True

しかし、私が得たのは:

$ ./test_meta.py
that: True
.that: True
.that: True
.that: True
.
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

私が見逃しているいくつかの閉鎖規則があるようです。これを回避するにはどうすればよいですか?より良いアプローチはありますか?

ありがとう、

編集:修正されました。スニペットを参照してください。

4

2 に答える 2

5

確かに、それは閉鎖の問題です:

変化する

attrs[testable_name] = lambda self: meth(self, arg)

attrs[testable_name] = lambda self,meth=meth,arg=arg: meth(self, arg)

デフォルト値を使用することによりarg、ラムダ内はargループの各反復中に設定されたデフォルト値にバインドされます。デフォルト値がない場合、ループのすべての反復が完了した後argの最後の値を取ります。arg(そして同じことがmeth)にも当てはまります。

于 2011-03-03T03:12:01.770 に答える
1

メタクラスルートに行くのではなく、この種のことのためにノーズテストジェネレーターを使用することを検討します:

http://somethingaboutorange.com/mrl/projects/nose/1.0.0/writing_tests.html#test-generators

テストジェネレーターの欠点は、それらがノーズ固有の機能であるため、stdlibの外部に依存関係を導入する必要があることです。利点は、書きやすく、理解しやすいと思うことです。

于 2011-03-03T02:39:19.667 に答える