前回はunittestモジュールの基本的な使い方について学習しました。今回はその続きで、テストパッケージの配置と実行方法、グループ化について解説します。
プロジェクト構成とテストの実行
Pythonに限らずプロジェクトの構成として、アプリケーションのソースコードとテストのソースコードは別パッケージとしてディレクトリを分けることが一般的です。以下のような構成の場合の実行方法について考えてみましょう。
. # プロジェクトディレクトリ(ここで実行する)
├── sample_lib # アプリケーションのパッケージ
│ ├── __init__.py
│ ├── mod1.py
│ └── mod2.py
└── test # テストのパッケージ
├── __init__.py
├── test_mod1.py
└── test_mod2.py
mod1.py、mod2.pyというコードに対するテストコードが用意されているものとします。これらのテストを実行する際、プロジェクトディレクトリ直下で以下のように-mオプションでunittestモジュールを実行し、相対パスでテストスクリプトを指定します。
$ python -m unittest test/test_mod1.py test_add_num . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK $ python -m unittest test/test_mod2.py test_is_positive . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
それぞれのテストスクリプトにif __name__ == '__main__':をつけて実行する方法もあるのですが、その場合はエントリーポイントがtestディレクトリ配下になってしまいますので、予めPYTHON_PATHをエクスポートするなどの措置が必要になります。
テストスイート(テストのグループ化)
上のプロジェクトの場合テストスクリプトがたった2つなので順番にpythonコマンドを実行しても良いのですが、プロジェクトによってはこれが数十、数百になることも考えられます。こういった時のためPythonはunittestをグループ化してまとめて実行することが可能です。(一般的にテストスイートと呼ばれています。)
テストスイートの作成方法
さっそくテストスイートを作成してみましょう。runner.pyという名前でテストクラスを作成します。
.
├── sample_lib
│ ├── __init__.py
│ ├── mod1.py
│ └── mod2.py
└── test
├── __init__.py
├── runner.py # テストスイートクラス
├── test_mod1.py
└── test_mod2.py
runner.pyは以下のように書きます。
# runner.py
import unittest
import test.test_mod1
import test.test_mod2
class TestRunner(unittest.TestCase):
def test_runner(self):
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(test.test_mod1.TestMod1))
test_suite.addTest(unittest.makeSuite(test.test_mod2.TestMod2))
unittest.TextTestRunner().run(test_suite)
unittest.TestSuite()オブジェクトを生成し、addTestでテストクラスを指定します。TextTestRunner().run()が呼び出されるとaddしたテストクラスが実行されます。
今までと同様に-mオプションをつけ、テストスイートクラスを指定すると、addしたテストケースが実行されていることが確認できます。
$ python -m unittest test/runner.py . . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK . ---------------------------------------------------------------------- Ran 1 test in 0.001s OK
discover(テストスイート作成の自動化)
上のテストスイートではaddTestで1つ1つ追加していきましたが、これもモジュール数が多いと管理が大変そうですね。このため、ディレクトリ単位でテストモジュールを探索し、自動でテストスイートを作成してくれる仕組みがあります。これをdiscoverと呼びます。
実はテストモジュールを指定せずに以下のように打ち込むと、プロジェクト全体を走査してテストを見つけ実行してくれます。
python -m unittest
ですが、サブプロジェクト単位でテストスイートを実行したい場合などは、上で作成したrunnerに自分でdiscoveryを記述してカスタマイズすることが可能です。上のrunner.pyをdiscoverを使用したものに修正してみましょう。
# runner.py
import unittest
import test.test_mod1
import test.test_mod2
class TestRunner(unittest.TestCase):
def test_runner(self):
test_suite = unittest.TestSuite()
# testクラスを見つけ出す
tests = unittest.defaultTestLoader.discover("test", pattern="test_*.py")
# 見つけたtestクラスを追加する
test_suite.addTest(tests)
unittest.TextTestRunner().run(test_suite)
discoverの引数にはディレクトリを指定します。ローカルでテストを実行する場合は、機能単位でテストをする等をして時間を節約することが可能です。
