標準 (Python) テストディスカバリーの変更

テスト収集中のパスの無視

コマンドラインの --ignore=path オプションを渡すことで、特定のテストディレクトリやモジュールを簡単に無視できます。 pytest は複数の --ignore オプションを許可します。 例:

tests/
|-- example
|   |-- test_example_01.py
|   |-- test_example_02.py
|   '-- test_example_03.py
|-- foobar
|   |-- test_foobar_01.py
|   |-- test_foobar_02.py
|   '-- test_foobar_03.py
'-- hello
    '-- world
        |-- test_world_01.py
        |-- test_world_02.py
        '-- test_world_03.py

例えば、pytest--ignore=tests/foobar/test_foobar_03.py --ignore=tests/hello/ として実行すると、指定されたパターンに一致しないテストモジュールのみが収集されます。

=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 5 items

tests/example/test_example_01.py .                                   [ 20%]
tests/example/test_example_02.py .                                   [ 40%]
tests/example/test_example_03.py .                                   [ 60%]
tests/foobar/test_foobar_01.py .                                     [ 80%]
tests/foobar/test_foobar_02.py .                                     [100%]

========================= 5 passed in 0.02 seconds =========================

--ignore-glob オプションを使用すると、Unixシェルスタイルのワイルドカードに基づいてテストファイルのパスを無視できます。 例えば、_01.py で終わるテストモジュールを除外するには、pytest--ignore-glob='*_01.py' で実行します。

テスト収集中にテストを除外する

--deselect=item オプションを渡すことで、個別にテストを除外できます。 例えば、tests/foobar/test_foobar_01.pytest_atest_b が含まれている場合、pytest--deselect tests/foobar/test_foobar_01.py::test_a で実行すると、tests/foobar/test_foobar_01.py::test_a 以外の全テストが実行されます。 複数の --deselect オプションも使用可能です。

コマンドラインで指定された重複パスの保持

pytest のデフォルト動作は、コマンドラインで指定された重複パスを無視することです。 例:

pytest path_a path_a

...
collected 1 item
...

テストを一度だけ収集する

重複したテストを収集するには、コマンドラインで --keep-duplicates オプションを使用します。 例:

pytest --keep-duplicates path_a path_a

...
collected 2 items
...

コレクタはディレクトリ単位で動作するため、同じテストファイルを2回指定すると、--keep-duplicates が指定されていなくても2回収集されます。 例:

pytest test_a.py test_a.py

...
collected 2 items
...

ディレクトリ再帰処理の変更

プロジェクトルートの ini ファイル(例: pytest.ini)で norecursedirs オプションを設定できます。

# content of pytest.ini
[pytest]
norecursedirs = .svn _build tmp*

これにより、pytest は通常の Subversion や sphinx-build ディレクトリ、または tmp で始まるディレクトリの再帰処理を行いません。

命名規則の変更

設定ファイル 内の python_filespython_classespython_functions を設定することで、異なる命名規則を構成できます。 例:

# content of pytest.ini
# Example 1: have pytest look for "check" instead of "test"
[pytest]
python_files = check_*.py
python_classes = Check
python_functions = *_check

これにより、pytestcheck_* .py に一致するファイル、クラスの Check プレフィックス、ならびに *_check に一致する関数・メソッド内のテストを探します。 例えば、

# content of check_myapp.py
class CheckMyApp:
    def simple_check(self):
        pass

    def complex_check(self):
        pass

テスト収集は次のようになります:

$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.ini
collected 2 items

<Dir pythoncollection.rst-206>
  <Module check_myapp.py>
    <Class CheckMyApp>
      <Function simple_check>
      <Function complex_check>

======================== 2 tests collected in 0.12s ========================

パターン同士の間にスペースを入れることで、複数のグロブパターンを指定できます:

# Example 2: have pytest look for files with "test" and "example"
# content of pytest.ini
[pytest]
python_files = test_*.py example_*.py

注釈

python_functions および python_classes オプションは、unittest.TestCase のテスト検出には影響しません。 pytest はテストケースメソッドの検出を unittest に委譲しているためです。

コマンドライン引数を Python パッケージとして解釈する

--pyargs オプションを使用すると、引数を Python パッケージ名として解釈し、対応するファイルシステムパスを導出してテストを実行します。 例えば、unittest2 をインストールしている場合、次のように入力できます:

pytest --pyargs unittest2.test.test_skipping -q

これにより対象のテストモジュールが実行されます。 他のオプション同様、ini ファイルの addopts オプションでこの設定を恒久的に変更できます:

# content of pytest.ini
[pytest]
addopts = --pyargs

pytest NAME とシンプルに実行すると、NAME がインポート可能なパッケージ/モジュールとして存在するか確認し、存在しなければファイルシステムパスとして扱われます。

収集内容の確認

テストを実行せずに収集ツリーを確認することも可能です:

. $ pytest --collect-only pythoncollection.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.ini
collected 3 items

<Dir pythoncollection.rst-206>
  <Dir CWD>
    <Module pythoncollection.py>
      <Function test_function>
      <Class TestClass>
        <Function test_method>
        <Function test_anothermethod>

======================== 3 tests collected in 0.12s ========================

テスト収集のカスタマイズ

すべての Python ファイルからテストを検出するように pytest に指示できます:

# content of pytest.ini
[pytest]
python_files = *.py

しかし、多くのプロジェクトにはインポートしたくない setup.py が存在します。 また、特定の Python バージョンでのみインポート可能なファイルもあるため、そのような場合は conftest.py ファイルに無視するファイルを動的に定義できます:

# content of conftest.py
import sys

collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
    collect_ignore.append("pkg/module_py2.py")

そして、このようなモジュールファイルがある場合:

# content of pkg/module_py2.py
def test_only_on_python2():
    try:
        assert 0
    except Exception, e:
        pass

さらに、このような setup.py のダミーファイルがある場合:

# content of setup.py
0 / 0  # will raise exception if imported

Python 2 インタプリタで実行すると、1つのテストが収集され、setup.py ファイルは除外されます:

#$ pytest --collect-only
====== test session starts ======
platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items
<Module 'pkg/module_py2.py'>
  <Function 'test_only_on_python2'>

====== 1 tests found in 0.04 seconds ======

Python 3 インタプリタで実行すると、1つのテストとともに setup.py ファイルも除外されます:

$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.ini
collected 0 items

======================= no tests collected in 0.12s ========================

また、Unix シェルスタイルのワイルドカードによるパターンを collect_ignore_glob に追加することで、ファイルを無視することも可能です。

以下の例では、Python 3 インタプリタ実行時に、conftest.pysetup.py および *_py2.py で終わるすべてのファイルを無視します。

# content of conftest.py
import sys

collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
    collect_ignore_glob = ["*_py2.py"]

Pytest 2.6 以降、ユーザーは __test__ 属性を False に設定することで、Test で始まるクラスを検出しないようにできます。

# Will not be discovered as a test
class TestClass:
    __test__ = False