ユニットテストを格納するディレクトリ「tests」のパッケージがあります。私のパッケージは次のようになります:
.
├── LICENSE
├── models
│ └── __init__.py
├── README.md
├── requirements.txt
├── tc.py
├── tests
│ ├── db
│ │ └── test_employee.py
│ └── test_tc.py
└── todo.txt
私のパッケージディレクトリから、tests/test_tc.py
とtests/db/test_employee.py
の両方を検索できるようにしたいと考えています。サードパーティのライブラリ(nose
など)をインストールしたり、TestSuite
を手動でビルドしてこれを実行したりする必要はありません。
確かに、テストが見つかったときにunittest discover
が停止しないように指示する方法はありますか? python -m unittest discover -s tests
はtests/test_tc.py
を検索し、python -m unittest discover -s tests/db
はtests/db/test_employee.py
を検索します。両方を見つける方法はありませんか?
少し掘り下げると、より深いモジュールがインポート可能である限り、それらはpython -m unittest discover
を介して発見されるようです。その場合の解決策は、__init__.py
ファイルを各ディレクトリに追加してパッケージにすることでした。
.
├── LICENSE
├── models
│ └── __init__.py
├── README.md
├── requirements.txt
├── tc.py
├── tests
│ ├── db
│ │ ├── __init__.py # NEW
│ │ └── test_employee.py
│ ├── __init__.py # NEW
│ └── test_tc.py
└── todo.txt
各ディレクトリに__init__.py
がある限り、python -m unittest discover
は関連するtest_*
モジュールをインポートできます。
テスト内に___init__.py
_ファイルを追加しても問題ない場合は、検出を処理する_load_tests
_関数をそこに配置できます。
テストパッケージ名(_
__init__.py
_を含むディレクトリ)がパターンに一致する場合、パッケージは 'load_tests'関数についてチェックされます。これが存在する場合、ローダー、テスト、パターンで呼び出されます。Load_testsが存在する場合、検出はパッケージにしない再帰します。load_testsは、パッケージ内のすべてのテストをロードします。
これが最良の方法であるとは思いませんが、その関数を記述する1つの方法は次のとおりです。
_import os
import pkgutil
import inspect
import unittest
# Add *all* subdirectories to this module's path
__path__ = [x[0] for x in os.walk(os.path.dirname(__file__))]
def load_tests(loader, suite, pattern):
for imp, modname, _ in pkgutil.walk_packages(__path__):
mod = imp.find_module(modname).load_module(modname)
for memname, memobj in inspect.getmembers(mod):
if inspect.isclass(memobj):
if issubclass(memobj, unittest.TestCase):
print("Found TestCase: {}".format(memobj))
for test in loader.loadTestsFromTestCase(memobj):
print(" Found Test: {}".format(test))
suite.addTest(test)
print("=" * 70)
return suite
_
かなり醜いです。
最初に、すべてのサブディレクトリをテストパッケージのパスに追加します( Docs )。
次に、 pkgutil
を使用してパスをたどり、パッケージまたはモジュールを探します。
見つかった場合は、モジュールメンバーをチェックして、それらがクラスであるかどうか、クラスである場合は_unittest.TestCase
_のサブクラスであるかどうかを確認します。そうであれば、クラス内のテストはテストスイートにロードされます。
したがって、プロジェクトルート内から次のように入力できます。
_python -m unittest discover -p tests
_
_-p
_パターンスイッチを使用する。すべてがうまくいけば、私が見たものを見ることができます。それは次のようなものです。
_Found TestCase: <class 'test_tc.TestCase'>
Found Test: testBar (test_tc.TestCase)
Found Test: testFoo (test_tc.TestCase)
Found TestCase: <class 'test_employee.TestCase'>
Found Test: testBar (test_employee.TestCase)
Found Test: testFoo (test_employee.TestCase)
======================================================================
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
_
これは予想どおりでした。私の2つのサンプルファイルには、それぞれtestFoo
とtestBar
の2つのテストが含まれていました。
編集:さらに掘り下げた後、この関数を次のように指定できるようです:
_def load_tests(loader, suite, pattern):
for imp, modname, _ in pkgutil.walk_packages(__path__):
mod = imp.find_module(modname).load_module(modname)
for test in loader.loadTestsFromModule(mod):
print("Found Tests: {}".format(test._tests))
suite.addTests(test)
_
これは、上記で使用したloader.loadTestsFromModule()
メソッドの代わりにloader.loadTestsFromTestCase()
メソッドを使用します。それでもtests
パッケージパスを変更し、モジュールを探して歩きます。これがここでの鍵だと思います。
見つかったテストスイートを一度にメインのテストスイートsuite
に追加しているため、出力は少し異なります。
_python -m unittest discover -p tests
Found Tests: [<test_tc.TestCase testMethod=testBar>, <test_tc.TestCase testMethod=testFoo>]
Found Tests: [<test_employee.TestCase testMethod=testBar>, <test_employee.TestCase testMethod=testFoo>]
======================================================================
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
_
ただし、両方のクラス、両方のサブディレクトリで、期待した4つのテストを引き続き取得します。