問題点として
特定の環境に依存するようなモジュールを内包するプロジェクトのテストにおいて、JenkinsやCircle CIのような環境ではテストが通らなくなってしまう。
解決する手段として
nose のテストを選択する仕組みを用い、環境ごとにテストを切り替えます。
使用するツール、サービス
- nose
- Circle CI
※Python 3.6 を使用します。
プロジェクトの構成
.
|____tests
| |____my_tools_tests
| | |____test_adder.py
| | |____test_pc.py
| | |____machine.py
|____my_tools
| |______init__.py
| |____adder.py
| |____pc.py
モジュール my_tools
モジュール my_tools には以下のクラスが入ります。
- adder.py: 加算器のクラス。
- pc.py: ホストのLinuxディストリビューション名等を取得する機能を持つクラス。
モジュール my_tools_tests
モジュール my_tools_tests には以下のクラスが入ります。
- test_adder.py: adder.py のテストを行うクラス。
- test_pc.py: pc.py のテストを行うクラス その1。 (テストを実行する環境に依存したコードを含む)
- machine.py: pc.py のテストを行うクラス その2。 (テストを実行する環境に依存したコードを含む)
テストの選択と切り替え
実行するテストを
- デコレーションによる方法
- ファイル名を直接指定する方法
の2パターンの方法で分岐させることができます。
attr での選択
以下のようにattrのデコレーションが付与されたテストは nose のオプションから実行する/しないを指定できます。
@attr('local')
def test_get_distribution(self) -> None:
pc = PC()
eq_("debian", pc.get_distribution())
このアノテーションが付与されたテストは nose のオプションから実行する/しないを指定できます。
@attr('local') が付けられたテストのみ実行する場合
nosetests --attr='local'
@attr('local') が付けられたテストは実行しない場合
nosetests --attr='!local'
ファイル名での選択
ファイル名に test がついていないユニットテストは、ファイルを指定しない限り実行されません。
引数でファイル名もしくはモジュール名を指定することで実行されます。
nosetests tests/my_tools_tests/machine.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
使い分けとして
通常は実行されるが、状況により特定のテストを実行しないようにする場合
attrを使用する。
nosetests --attr='!local'
通常は実行されないが、状況により特定のテストを実行する場合
ファイル名を選択する。
nosetests tests/my_tools_tests/machine.py
別環境での実行
my_tools/pc.py および machine.py は Linux(Ubuntu) に依存したコードです。
Jenkins や Circle CI などからテストを実行する場合、環境に依存するコードは適切にテストができない可能性があります。
また逆に、開発環境ではテストできないコードを別のホストで実行する場合もあります。
このような場合に前述のテストの選択と切り替えにより、適切にテストが実行されるよう調整することができます。
一例として、Circle CIでの設定を取り上げます。
steps:
- run:
name: Run tests
command: nosetests --attr='!local'
ここでは --attr によりテストを選択しています。
結果として
テストを行う環境ごとに実行するテストが選択できるようになります。