目次

前のトピックへ

モジュールやテストファイルの doctest

次のトピックへ

講演とチュートリアル

プラグインと conftest ファイルの連携

py.test は よく練られたフック を呼び出すことにより、設定、コレクション、実行、レポートの全箇所で処理を実装します。事実上、任意の Python モジュールをプラグインとして登録できます。このプラグインは、フック関数の区別や検出を容易にして pytest_ という接頭辞をもつ全フック関数から任意のフック関数 (通常は2つか3つ) を実装します。3つの基本的な配置場所があります:

conftest.py: ディレクトリ毎のローカルプラグイン

ローカルの conftest.py プラグインは、ディレクトリ固有のフック実装を含みます。セッションとテストの実行処理は、ファイルシステムのルートディレクトリに近い conftest.py ファイルで定義された全てのフックを実行します。ファイルを次の場所に置くと仮定してください:

a/conftest.py:
    def pytest_runtest_setup(item):
        # 'a' ディレクトリにある各テストの実行向けに呼ばれる
        print ("setting up", item)

a/test_in_subdir.py:
    def test_sub():
        pass

test_flat.py:
    def test_flat():
        pass

このコードの実行方法です:

py.test test_flat.py   # "setting up" を表示しない
py.test a/test_sub.py  # "setting up" を表示

ノート

Python パッケージディレクトリ (例えば __Init__.py を含むディレクトリ) に置かれてない conftest.py ファイルがある場合、PYTHONPATH または sys.path に同じ名前をもつ別の conftest.py ファイルを置く可能性があり、”import conftest” が曖昧になるときがあります。こういったプロジェクトでは、パッケージスコープの中で conftest.py を置くか conftest.py ファイルから決してインポートしないかのどちらか一方を選択するのが良いプラクティスです。

外部プラグインのインストールと探索

プラグインのインストールは、普通の Python インストールツールを使って行います。例えば:

pip install pytest-NAME
pip uninstall pytest-NAME

プラグインがインストール済みなら、py.test が自動的に検出してそのプラグインを組み込みます。プラグインを有効化する必要はありません。既知のプラグイン一覧を紹介します:

  • pytest-capturelog: logging モジュールからのメッセージに関するアサートやキャプチャ
  • pytest-cov: 分散テストでの互換性やカバレッジレポート
  • pytest-pep8: --pep8 オプションを使った PEP8 規約チェック
  • oejskit: 実際のブラウザーで javascript の unittests を実行するプラグイン (バージョン 0.8.9 は pytest-2.0 では互換性がありません )

“pytest-” で pypi.python.org を検索 すると、もっとプラグインが見つかるでしょう。

サンプルによるプラグインの記述

自分でプラグインを作成したいなら、たくさんある実際のプラグインをコピーしてから始めると良いです:

これらの全プラグインは、機能を追加/拡張するためにドキュメント付きの よく練られたフック を実装します。

独自プラグインを他からインストール可能にする

自分で作成したプラグインを外部から利用できるようにしたいなら、 py.test がプラグインモジュールを見つけられるように、ディストリビューションのいわゆるエントリーポイントを定義します。エントリーポイントは setuptools または distribute が提供する機能です。py.test は、プラグインを検出するために pytest11 というエントリーポイントを調べます。このように setuptools/distribute の setup 処理でエントリーポイントを定義することにより、自分のプラグインを利用できます。

# サンプルの ./setup.py ファイル
from setuptools import setup

setup(
    name="myproject",
    packages = ['myproject']

    # 次のように記述して py.test からプラグインを利用可能にする
    entry_points = {
        'pytest11': [
            'name_of_plugin = myproject.pluginmodule',
        ]
    },
)

パッケージがこの方法でインストールされる場合、py.test は よく練られたフック を定義するプラグインとして myproject.pluginmodule を読み込みます。

ツール起動時のプラグイン検出順序

py.test は、次の方法でツール起動時にプラグインモジュールを読み込みます。

  • 全ての組み込みプラグインを読み込む。
  • コマンドラインの -p name オプションを事前に調べ、実際にコマンドラインの引数解析を行う前に指定したプラグインを読み込む。
  • コマンドラインの実行で推定される全ての conftest.py ファイルを読み込む (テストファイルと全ての ディレクトリ) 。 サブ ディレクトリからの conftest.py ファイルは、デフォルトでは、ツールの起動時に読み込まれないことに注意してください。
  • conftest.py ファイルの pytest_plugins 変数で指定された全てのプラグインを再帰的に読み込む

テストモジュールまたは conftest ファイルのプラグインの要求と読み込み

テストモジュール、または conftest ファイル内でプラグインを要求できます:

pytest_plugins = "name1", "name2",

テストモジュール、または conftest プラグインが読み込まれるとき、指定したプラグインも同様に読み込まれます。さらに次のようにドット区切りのパスも使えます:

pytest_plugins = "myapp.testsupport.myplugin"

これは py.test プラグインとして指定したモジュールをインポートします。

プラグイン名で別のプラグインへアクセス

あるプラグインと別のプラグインのコードを協調させたいなら、次のようにプラグインマネージャーを使ってリファレンスを取得できます:

plugin = config.pluginmanager.getplugin("name_of_plugin")

既存のプラグイン名を調べたい場合は --traceconfig オプションを使ってください。

有効なプラグインの検出

自分の環境で有効なプラグインを調べたいなら、次のように実行してください:

py.test --traceconfig

有効なプラグインとその名前を表示する拡張テストヘッダーを取得します。 conftest.py が読み込まれるときにそのローカルプラグインも表示します。

名前からプラグインの無効化や登録解除

プラグインを読み込ませない、または登録を解除できます:

py.test -p no:NAME

このオプションは、有効化/読み込もうとするプラグインが既に存在するものとして扱います。プラグイン名を取得する方法は 有効なプラグインの検出 を参照してください。

py.test のデフォルトのプラグインリファレンス

次のプラグインのソースコードが pytest リポジトリ に含まれています。

_pytest.assertion support for presenting detailed information in failing assertions.
_pytest.capture per-test stdout/stderr capturing mechanisms, capsys and capfd function arguments.
_pytest.config command line options, ini-file and conftest.py processing.
_pytest.doctest discover and run doctests in modules and test files.
_pytest.genscript generate a single-file self-contained version of py.test
_pytest.helpconfig version info, help messages, tracing configuration.
_pytest.junitxml report test results in JUnit-XML format, for use with Hudson and build integration servers.
_pytest.mark generic mechanism for marking and selecting python functions.
_pytest.monkeypatch monkeypatching and mocking functionality.
_pytest.nose run test suites written for nose.
_pytest.pastebin submit failure or test session information to a pastebin service.
_pytest.pdb interactive debugging with PDB, the Python Debugger.
_pytest.pytester (disabled by default) support for testing py.test and py.test plugins.
_pytest.python Python test discovery, setup and run of test functions.
_pytest.recwarn recording warnings during test function execution.
_pytest.resultlog (disabled by default) create result information in a plain text file.
_pytest.runner basic collect and runtest protocol implementations
_pytest.main core implementation of testing process: init, session, runtest loop.
_pytest.skipping support for skip/xfail functions and markers.
_pytest.terminal terminal reporting of the full testing process.
_pytest.tmpdir support for providing temporary directories to test functions.
_pytest.unittest discovery and running of std-library “unittest” style tests.

py.test のフックリファレンス

フックの仕様と検証

py.test は、初期化、テスト実行、レポートを実装するフック関数を呼び出します。py.test がプラグインを読み込むとき、各フック関数名はその対応するフック仕様を確認します。各フック関数名とその引数の名前は、フック仕様に一致する必要があります。但し、フック関数を単に指定しないことにより 少ない パラメーターは許容します。引数の名前やフック名そのものを誤入力した場合、利用できる引数を表示するエラーが表示されます。

初期化、コマンドライン、設定のフック

_pytest.hookspec.pytest_cmdline_preparse(config, args)[ソース]

modify command line arguments before option parsing.

_pytest.hookspec.pytest_cmdline_parse(pluginmanager, args)[ソース]

return initialized config object, parsing the specified args.

_pytest.hookspec.pytest_namespace()[ソース]

return dict of name->object to be made globally available in the py.test/pytest namespace. This hook is called before command line options are parsed.

_pytest.hookspec.pytest_addoption(parser)[ソース]

add optparse-style options and ini-style config values via calls to parser.addoption and parser.addini(...).

_pytest.hookspec.pytest_cmdline_main(config)[ソース]

called for performing the main command line action. The default implementation will invoke the configure hooks and runtest_mainloop.

_pytest.hookspec.pytest_configure(config)[ソース]

called after command line options have been parsed. and all plugins and initial conftest files been loaded.

_pytest.hookspec.pytest_unconfigure(config)[ソース]

called before test process is exited.

汎用的な “runtest” フック

フックに関連する全ての runtest は pytest.Item オブジェクトを受け取ります。

_pytest.hookspec.pytest_runtest_protocol(item, nextitem)[ソース]

implements the runtest_setup/call/teardown protocol for the given test item, including capturing exceptions and calling reporting hooks.

パラメタ:
  • item – test item for which the runtest protocol is performed.
  • nexitem – the scheduled-to-be-next test item (or None if this is the end my friend). This argument is passed on to pytest_runtest_teardown().
Return boolean:

True if no further hook implementations should be invoked.

_pytest.hookspec.pytest_runtest_setup(item)[ソース]

called before pytest_runtest_call(item).

_pytest.hookspec.pytest_runtest_call(item)[ソース]

called to execute the test item.

_pytest.hookspec.pytest_runtest_teardown(item, nextitem)[ソース]

called after pytest_runtest_call.

パラメタ:nexitem – the scheduled-to-be-next test item (None if no further test item is scheduled). This argument can be used to perform exact teardowns, i.e. calling just enough finalizers so that nextitem only needs to call setup-functions.
_pytest.hookspec.pytest_runtest_makereport(item, call)[ソース]

return a _pytest.runner.TestReport object for the given pytest.Item and _pytest.runner.CallInfo.

より深く理解するには _pytest.runner の実際のフックのデフォルト実装を調べることになるかもしれません。さらに、テストが失敗したときにそのまま対話式のデバッガーに入る、その入出力のキャプチャや _pytest.capture と相互にやり取りする _pytest.pdb もきっと見たくなるでしょう。

実際にレポートを行う _pytest.terminal は、テスト実行に関する情報を表示するためにレポートフックを使います。

コレクションのフック

py.test はファイルとディレクトリを探索するために次のフックを呼び出します:

_pytest.hookspec.pytest_ignore_collect(path, config)[ソース]

return True to prevent considering this path for collection. This hook is consulted for all files and directories prior to calling more specific hooks.

_pytest.hookspec.pytest_collect_directory(path, parent)[ソース]

called before traversing a directory for collection files.

_pytest.hookspec.pytest_collect_file(path, parent)[ソース]

return collection Node or None for the given path. Any new node needs to have the specified parent as a parent.

Python モジュール内のオブジェクトのコレクションに影響を与えるには、次のフックが使えます:

_pytest.hookspec.pytest_pycollect_makeitem(collector, name, obj)[ソース]

return custom item/collector for a python object in a module, or None.

レポートフック

レポートフックに関連するセッション:

_pytest.hookspec.pytest_collectstart(collector)[ソース]

collector starts collecting.

_pytest.hookspec.pytest_itemcollected(item)[ソース]

we just collected a test item.

_pytest.hookspec.pytest_collectreport(report)[ソース]

collector finished collecting.

_pytest.hookspec.pytest_deselected(items)[ソース]

called for test items deselected by keyword.

そして、テストの実行に関する中央のフックです:

_pytest.hookspec.pytest_runtest_logreport(report)[ソース]

process a test setup/call/teardown report relating to the respective phase of executing a test.

フックで実行される重要なオブジェクトのリファレンス

class _pytest.config.Config(pluginmanager=None)[ソース]

access to configuration values, pluginmanager and plugin hooks.

addinivalue_line(name, line)[ソース]

add a line to an ini-file option. The option must have been declared but might not yet be set in which case the line becomes the the first line in its value.

classmethod fromdictargs(option_dict, args)[ソース]

constructor useable for subprocesses.

getini(name)[ソース]

return configuration value from an ini file. If the specified name hasn’t been registered through a prior parse.addini call (usually from a plugin), a ValueError is raised.

getvalue(name, path=None)[ソース]

return name value looked set from command line options.

(deprecated) if we can’t find the option also lookup the name in a matching conftest file.

getvalueorskip(name, path=None)[ソース]

(deprecated) return getvalue(name) or call py.test.skip if no value exists.

option = None

command line option values, usually added via parser.addoption(...) or parser.getgroup(...).addoption(...) calls

pluginmanager = None

a pluginmanager instance

class _pytest.config.Parser(usage=None, processopt=None)[ソース]

Parser for command line arguments.

addini(name, help, type=None, default=None)[ソース]

add an ini-file option with the given name and description.

addoption(*opts, **attrs)[ソース]

add an optparse-style option.

getgroup(name, description='', after=None)[ソース]

get (or create) a named option Group.

Name :unique name of the option group.
Description :long description for –help output.
After :name of other group, used for ordering –help output.
class _pytest.main.Node(name, parent)[ソース]

base class for all Nodes in the collection tree. Collector subclasses have children, Items are terminal nodes.

Class

deprecated attribute ‘Class’, use pytest.Class

File

deprecated attribute ‘File’, use pytest.File

Function

deprecated attribute ‘Function’, use pytest.Function

Instance

deprecated attribute ‘Instance’, use pytest.Instance

Item

deprecated attribute ‘Item’, use pytest.Item

Module

deprecated attribute ‘Module’, use pytest.Module

config = None

the test config object

fspath = None

filesystem path where this node was collected from

listchain()[ソース]

return list of all parent collectors up to self, starting from root of collection tree.

name = None

a unique name with the scope of the parent

parent = None

the parent collector node.

session = None

the collection this node is part of

class _pytest.runner.CallInfo(func, when)[ソース]

Result/Exception info a function invocation.

excinfo = None

None or ExceptionInfo object.

when = None

context of invocation: one of “setup”, “call”, “teardown”, “memocollect”

class _pytest.runner.TestReport(nodeid, location, keywords, outcome, longrepr, when, sections=(), duration=0, **extra)[ソース]

Basic test report object (also used for setup and teardown calls if they fail).

duration = None

time it took to run just the test

keywords = None

a name -> value dictionary containing all keywords and markers associated with a test invocation.

location = None

a (filesystempath, lineno, domaininfo) tuple indicating the actual location of a test item - it might be different from the collected one e.g. if a method is inherited from a different module.

longrepr = None

None or a failure representation.

nodeid = None

normalized collection node id

outcome = None

test outcome, always one of “passed”, “failed”, “skipped”.

sections = None

list of (secname, data) extra information which needs to marshallable

when = None

one of ‘setup’, ‘call’, ‘teardown’ to indicate runtest phase.