@Yasuwo

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Python unittest の load_tests プロトコルにおけるテストの削除方法について

解決したいこと

Python の unittest について、モジュールやパッケージレベルで
テストディスカバリのロードをカスタマイズできる load_tests プロトコル があります。
このプロトコルにおいて、自動的に発見されたテスト群から任意のテストを除去するベストプラクティスを知りたいと考えています。

load_tests プロトコル

モジュールやパッケージには、load_tests と呼ばれる関数を実装できます。これにより、通常のテスト実行時やテストディスカバリ時のテストのロードされ方をカスタマイズできます。

テストモジュールが load_tests を定義していると、それが TestLoader.loadTestsFromModule() から呼ばれます。引数は以下です:

load_tests(loader, standard_tests, pattern)

pattern は loadTestsFromModule からそのまま渡されます。デフォルトは None です。

これは TestSuite を返すべきです。

loader はローディングを行う TestLoader のインスタンスです。 standard_tests は、そのモジュールからデフォルトでロードされるテストです。これは、テストの標準セットのテストの追加や削除のみを行いたいテストモジュールに一般に使われます。第三引数は、パッケージをテストディスカバリの一部としてロードするときに使われます。

発生している問題・エラー

standard_tests として受け取り、かつ、 load_tests が返すべき TestSuite クラスは、
すでに自分が保持している任意のテストを削除する方法を公開していないように思えます。

In [1]: from unittest import TestSuite

In [2]: dir(TestSuite)
Out[2]:
['__call__',
 (中略)
 '_addClassOrModuleLevelException',
 '_cleanup',
 '_createClassOrModuleLevelException',
 '_get_previous_module',
 '_handleClassSetUp',
 '_handleModuleFixture',
 '_handleModuleTearDown',
 '_removeTestAtIndex',
 '_tearDownPreviousClass',
 'addTest',
 'addTests',
 'countTestCases',
 'debug',
 'run']

load_tests プロトコルにおいて、任意のテストを削除するにはどのようにするのがベストプラクティスでしょうか?

自分で試したこと(案)

案1: 内部変数を直接いじる、あるいは、内部メソッドを呼ぶ

TestSuite は 内部変数 _tests リストとしてテストを保持し、
また、_removeTestAtIndex メソッドを持っているので、これを直接いじる案があるとは思います。

class BaseTestSuite(object):
    def __init__(self, tests=()):
        self._tests = []
        self._removed_tests = 0
        self.addTests(tests)
    def _removeTestAtIndex(self, index):
        """Stop holding a reference to the TestCase at index."""
class TestSuite(BaseTestSuite):
    ...

しかし、これらは内部変数または内部メソッドであるため、直接いじるのは望ましくないと考えています。

案2: TestSuiteを自前で再作成する

これがベストプラクティスな気はしているのですが、あまり直感的ではないと感じています。

def load_tests(loader, standard_tests, pattern):
    return TestSuite([
        test
        for test
        in standard_tests
        if check_to_run(loader, test, pattern)
    ])
def check_to_run(loader, test, pattern) -> bool:
    """テストを実行すべきか判定する"""
    ...

ただ、ここまで書いて思いましたが、 standard_tests というのは名前の通り、
標準的にロードされるテストを格納している変数であるべきで、
任意のテストをそこから削除するのは好ましくないでは、
よって、やはり案2が自然なのでは、と考えています。
お知恵を拝借できれば幸いです。

0 likes

No Answers yet.

Your answer might help someone💌