フィクスチャのリファレンス¶
参考
参考
組み込みフィクスチャ¶
フィクスチャ は @pytest.fixture デコレータを使用して定義されます。 Pytest にはいくつかの便利な組み込みフィクスチャがあります:
capfdファイルディスクリプタ 1 と 2 に出力されるテキストをキャプチャします。
capfdbinaryファイルディスクリプタ 1 と 2 に出力されるバイトをキャプチャします。
caplogログの制御とログエントリへのアクセス。
capsyssys.stdout と sys.stderr に出力されるテキストをキャプチャします。
capsysbinarysys.stdout と sys.stderr に出力されるバイトをキャプチャします。
cachepytest の実行間で値を保存および取得します。
doctest_namespacedoctest の名前空間に挿入される dict を提供します。
monkeypatchクラス、関数、辞書、os.environ などのオブジェクトを一時的に変更します。
pytestconfig設定値、pluginmanager、およびプラグインフックへのアクセス。
record_propertyテストに追加のプロパティを追加します。
record_testsuite_propertyテストスイートに追加のプロパティを追加します。
recwarnテスト関数によって発行された警告を記録します。
request実行中のテスト関数に関する情報を提供します。
testdirpytest プラグインの実行とテストを支援するための一時的なテストディレクトリを提供します。
tmp_path各テスト関数に固有の一時ディレクトリへの
pathlib.Pathオブジェクトを提供します。tmp_path_factoryセッションスコープの一時ディレクトリを作成し、
pathlib.Pathオブジェクトを返します。tmpdir各テスト関数に固有の一時ディレクトリへの py.path.local オブジェクトを提供します。
tmp_pathに置き換えられました。tmpdir_factoryセッションスコープの一時ディレクトリを作成し、py.path.local オブジェクトを返します。
tmp_path_factoryに置き換えられました。
フィクスチャの利用可能性¶
フィクスチャの利用可能性はテストの視点から決定されます。 フィクスチャは、そのフィクスチャが定義されているスコープ内にある場合にのみ、テストでリクエストできます。 フィクスチャがクラス内に定義されている場合、そのクラス内のテストでのみリクエストできます。 しかし、フィクスチャがモジュールのグローバルスコープ内に定義されている場合、そのモジュール内のすべてのテスト (クラス内に定義されている場合でも) でリクエストできます。
同様に、テストはそのテストが定義されているスコープ内にある場合にのみ、自動使用フィクスチャの影響を受けることができます (自動使用フィクスチャはそのスコープ内で最初に実行される を参照)。
フィクスチャは、テストが関与するすべてのフィクスチャを参照できる限り、どこに定義されていても他のフィクスチャをリクエストできます。
例えば、スコープ外のフィクスチャ (inner) をリクエストするフィクスチャ (outer) を含むテストファイルは次のようになります:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def outer(order, inner):
order.append("outer")
class TestOne:
@pytest.fixture
def inner(self, order):
order.append("one")
def test_order(self, order, outer):
assert order == ["one", "outer"]
class TestTwo:
@pytest.fixture
def inner(self, order):
order.append("two")
def test_order(self, order, outer):
assert order == ["two", "outer"]
テストの視点から見ると、依存している各フィクスチャを問題なく参照できます:
したがって、テストが実行されるとき、pytest はテストの視点から検索するため、outer は inner を問題なく見つけることができます。
注釈
フィクスチャが定義されているスコープは、そのインスタンス化の順序には影響しません。 順序は こちら で説明されているロジックによって決定されます
conftest.py: 複数のファイル間でフィクスチャを共有する¶
conftest.py ファイルは、ディレクトリ全体にフィクスチャを提供する手段として機能します。 conftest.py に定義されたフィクスチャは、そのパッケージ内の任意のテストでインポートすることなく使用できます (pytest が自動的にそれらを検出します)。
複数のネストされたディレクトリ/パッケージにテストを含めることができ、各ディレクトリには独自のフィクスチャを持つ独自の conftest.py を持つことができ、親ディレクトリの conftest.py ファイルによって提供されるフィクスチャに追加されます。
例えば、次のようなテストファイル構造がある場合:
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def top(order, innermost):
order.append("top")
test_top.py
# content of tests/test_top.py
import pytest
@pytest.fixture
def innermost(order):
order.append("innermost top")
def test_order(order, top):
assert order == ["innermost top", "top"]
subpackage/
__init__.py
conftest.py
# content of tests/subpackage/conftest.py
import pytest
@pytest.fixture
def mid(order):
order.append("mid subpackage")
test_subpackage.py
# content of tests/subpackage/test_subpackage.py
import pytest
@pytest.fixture
def innermost(order, mid):
order.append("innermost subpackage")
def test_order(order, top):
assert order == ["mid subpackage", "innermost subpackage", "top"]
スコープの境界は次のように視覚化できます:
ディレクトリはそれ自体がスコープの一種となり、そのディレクトリ内の conftest.py ファイルに定義されたフィクスチャがそのスコープ全体で利用可能になります。
テストはフィクスチャを探すために上方向 (円の外側) に検索することが許可されていますが、下方向 (円の内側) に検索を続けることはできません。 したがって、tests/subpackage/test_subpackage.py::test_order は tests/subpackage/test_subpackage.py に定義された innermost フィクスチャを見つけることができますが、tests/test_top.py に定義されたフィクスチャは見つけることができません。
テストが最初に見つけたフィクスチャが使用されるため、特定のスコープに対してフィクスチャを変更または拡張する必要がある場合は、フィクスチャをオーバーライドする ことができます。
また、conftest.py ファイルを使用して ローカルなディレクトリごとのプラグイン を実装することもできます。
サードパーティプラグインからのフィクスチャ¶
ただし、フィクスチャはこの構造で定義されていなくてもテストで利用可能です。 サードパーティプラグインによって提供されることもあり、多くの pytest プラグインがこの方法で動作します。 これらのプラグインがインストールされている限り、それらが提供するフィクスチャはテストスイートのどこからでもリクエストできます。
これらのフィクスチャはテストスイートの構造外から提供されるため、サードパーティプラグインは conftest.py ファイルやテストスイート内のディレクトリのようなスコープを実際には提供しません。 その結果、pytest は前述のようにスコープを通じてフィクスチャを検索し、最後にプラグインに定義されたフィクスチャに到達します。
例えば、次のファイル構造があるとします:
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def order():
return []
subpackage/
__init__.py
conftest.py
# content of tests/subpackage/conftest.py
import pytest
@pytest.fixture(autouse=True)
def mid(order, b_fix):
order.append("mid subpackage")
test_subpackage.py
# content of tests/subpackage/test_subpackage.py
import pytest
@pytest.fixture
def inner(order, mid, a_fix):
order.append("inner subpackage")
def test_order(order, inner):
assert order == ["b_fix", "mid subpackage", "a_fix", "inner subpackage"]
plugin_a がインストールされていて a_fix フィクスチャを提供し、plugin_b がインストールされていて b_fix フィクスチャを提供している場合、テストのフィクスチャ検索は次のようになります:
pytest は最初に tests/ 内のスコープで a_fix と b_fix を検索し、その後にプラグインで検索します。
フィクスチャのインスタンス化順序¶
pytest がテストを実行しようとするとき、どのフィクスチャが実行されるかがわかると、それらが実行される順序を決定する必要があります。 これを行うために、pytest は次の3つの要素を考慮します:
スコープ
依存関係
自動使用
フィクスチャやテストの名前、それらが定義されている場所、定義されている順序、フィクスチャがリクエストされる順序は、偶然以外の実行順序には影響しません。 pytest はこれらの偶然が実行ごとに一貫していることを確認しようとしますが、それに依存するべきではありません。 順序を制御したい場合は、これらの3つの要素に依存し、依存関係が明確に確立されていることを確認するのが最も安全です。
高スコープのフィクスチャが最初に実行される¶
フィクションリクエスト内では、高スコープ (例えば session) のフィクスチャが低スコープ (例えば function や class) のフィクスチャよりも先に実行されます。
例を示します:
from __future__ import annotations
import pytest
@pytest.fixture(scope="session")
def order():
return []
@pytest.fixture
def func(order):
order.append("function")
@pytest.fixture(scope="class")
def cls(order):
order.append("class")
@pytest.fixture(scope="module")
def mod(order):
order.append("module")
@pytest.fixture(scope="package")
def pack(order):
order.append("package")
@pytest.fixture(scope="session")
def sess(order):
order.append("session")
class TestClass:
def test_order(self, func, cls, mod, pack, sess, order):
assert order == ["session", "package", "module", "class", "function"]
テストは、より大きなスコープのフィクスチャが最初に実行されるため、成功します。
順序は次のようになります:
同じ順序のフィクスチャは依存関係に基づいて実行される¶
フィクスチャが他のフィクスチャをリクエストすると、そのフィクスチャが最初に実行されます。 したがって、フィクスチャ a がフィクスチャ b をリクエストすると、フィクスチャ b が最初に実行されます。 なぜなら、a は b に依存しており、b なしでは動作できないからです。 a が b の結果を必要としない場合でも、b の後に実行される必要がある場合は b をリクエストできます。
例えば:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def a(order):
order.append("a")
@pytest.fixture
def b(a, order):
order.append("b")
@pytest.fixture
def c(b, order):
order.append("c")
@pytest.fixture
def d(c, b, order):
order.append("d")
@pytest.fixture
def e(d, b, order):
order.append("e")
@pytest.fixture
def f(e, order):
order.append("f")
@pytest.fixture
def g(f, c, order):
order.append("g")
def test_order(g, order):
assert order == ["a", "b", "c", "d", "e", "f", "g"]
依存関係をマッピングすると、次のようになります:
各フィクスチャが従うべきルール (各フィクスチャがどのフィクスチャの後に来る必要があるか) は包括的であり、次のようにフラット化できます:
pytest が明確で線形な依存関係のチェーンを把握できるようにするために、これらのリクエストを通じて十分な情報が提供される必要があります。 曖昧さがあり、操作の順序が複数の方法で解釈できる場合、pytest はその時点で任意の解釈を選択する可能性があると考えるべきです。
例えば、d が c をリクエストしなかった場合、グラフは次のようになります:
c をリクエストしたのは g だけであり、g は f もリクエストしているため、c が f、e、または d の前後のどこに配置されるべきかが不明確です。 c に設定された唯一のルールは、b の後、g の前に実行される必要があるということです。
pytest はこの場合、c がどこに配置されるべきかを知らないため、b と g の間のどこにでも配置される可能性があると考えるべきです。
これは必ずしも悪いことではありませんが、覚えておくべきことです。 実行順序がテストのターゲットとなる動作に影響を与える可能性がある場合、またはテストの結果に影響を与える可能性がある場合は、その順序を明確に定義し、pytest がその順序を線形化/「フラット化」できるようにする必要があります。
自動使用フィクスチャはそのスコープ内で最初に実行される¶
自動使用フィクスチャは、それを参照できるすべてのテストに適用されると見なされるため、そのスコープ内の他のフィクスチャよりも先に実行されます。 自動使用フィクスチャによってリクエストされたフィクスチャは、実際の自動使用フィクスチャが適用されるテストに対して自動使用フィクスチャ自体になります。
したがって、フィクスチャ a が自動使用であり、フィクスチャ b がそうでない場合でも、フィクスチャ a がフィクスチャ b をリクエストすると、フィクスチャ b は実質的に自動使用フィクスチャとなりますが、a が適用されるテストに対してのみです。
前の例では、d が c をリクエストしなかった場合、グラフは不明確になりました。 しかし、c が自動使用であれば、b と a も実質的に自動使用となります。 なぜなら、c がそれらに依存しているからです。 その結果、それらはそのスコープ内の非自動使用フィクスチャの上にシフトされます。
したがって、テストファイルが次のようになっている場合:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def a(order):
order.append("a")
@pytest.fixture
def b(a, order):
order.append("b")
@pytest.fixture(autouse=True)
def c(b, order):
order.append("c")
@pytest.fixture
def d(b, order):
order.append("d")
@pytest.fixture
def e(d, order):
order.append("e")
@pytest.fixture
def f(e, order):
order.append("f")
@pytest.fixture
def g(f, c, order):
order.append("g")
def test_order_and_g(g, order):
assert order == ["a", "b", "c", "d", "e", "f", "g"]
グラフは次のようになります:
c がグラフ内で d の上に配置できるようになったため、pytest は再びグラフを次のように線形化できます:
この例では、c が b と a を実質的に自動使用フィクスチャにします。
ただし、自動使用には注意が必要です。 自動使用フィクスチャは、それを参照できるすべてのテストに対して自動的に実行されます。 たとえそれらがリクエストされていなくてもです。 例えば、次のファイルを考えてみてください:
from __future__ import annotations
import pytest
@pytest.fixture(scope="class")
def order():
return []
@pytest.fixture(scope="class", autouse=True)
def c1(order):
order.append("c1")
@pytest.fixture(scope="class")
def c2(order):
order.append("c2")
@pytest.fixture(scope="class")
def c3(order, c1):
order.append("c3")
class TestClassWithC1Request:
def test_order(self, order, c1, c3):
assert order == ["c1", "c3"]
class TestClassWithoutC1Request:
def test_order(self, order, c2):
assert order == ["c1", "c2"]
TestClassWithoutC1Request 内のテストは何も c1 をリクエストしていないにもかかわらず、それでも実行されます:
ただし、1つの自動使用フィクスチャが非自動使用フィクスチャをリクエストしたからといって、その非自動使用フィクスチャがそれが適用されるすべてのコンテキストに対して自動使用フィクスチャになるわけではありません。 それは、実際の自動使用フィクスチャ (非自動使用フィクスチャをリクエストしたもの) が適用されるコンテキストに対してのみ実質的に自動使用フィクスチャになります。
例えば、次のテストファイルを見てみましょう:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def c1(order):
order.append("c1")
@pytest.fixture
def c2(order):
order.append("c2")
class TestClassWithAutouse:
@pytest.fixture(autouse=True)
def c3(self, order, c2):
order.append("c3")
def test_req(self, order, c1):
assert order == ["c2", "c3", "c1"]
def test_no_req(self, order):
assert order == ["c2", "c3"]
class TestClassWithoutAutouse:
def test_req(self, order, c1):
assert order == ["c1"]
def test_no_req(self, order):
assert order == []
次のように分解されます:
TestClassWithAutouse 内の test_req と test_no_req に対して、c3 は c2 を実質的に自動使用フィクスチャにします。 これが、c2 と c3 がリクエストされていないにもかかわらず両方のテストで実行される理由であり、test_req に対して c1 の前に c2 と c3 が実行される理由です。
これが c2 を 実際の 自動使用フィクスチャにした場合、TestClassWithoutAutouse 内のテストに対しても c2 が実行されます。 なぜなら、それらが c2 を参照できるからです。 しかし、そうではありません。 なぜなら、TestClassWithoutAutouse のテストの観点からは、c2 は自動使用フィクスチャではないからです。 なぜなら、それらは c3 を見ることができないからです。