複数のファイルの複数のクラスにあるpy.testによって実行される複数のテストがあります。
Py.testで使用されるすべてのファイルのすべてのクラスのすべてのメソッドで、大規模な辞書(複製したくない)を共有する最も簡単な方法は何ですか?
つまり、すべてのテストに対して「グローバル変数」を作成する必要があります。 py.test以外では、この変数を使用しないので、テスト対象のファイルに保存したくありません。私はpy.testのフィクスチャを頻繁に使用しましたが、これはこの必要性にとってはやり過ぎのようです。たぶんそれが唯一の方法ですか?
更新: pytest-namespaceフックは非推奨/削除されました 。使用しないでください。詳細については、 #3735 を参照してください。
フィクスチャーを使用するという明らかで魔法のないオプションについて言及します。モジュールのpytestmark = pytest.mark.usefixtures('big_dict')
を使用してモジュール全体に適用できますが、名前空間にはないので、明示的に要求するのが最適です。
または、フックを使用してpytest名前空間に物を割り当てることができます:
# conftest.py
def pytest_namespace():
return {'my_big_dict': {'foo': 'bar'}}
そして今、あなたはpytest.my_big_dict
。ただし、フィクスチャはおそらくまだまだ優れています。
Py.testには好きなものが山ほどありますが、絶対に嫌いなことの1つは、コードインテリジェンスツールでのプレイの質の低さです。 declare変数の自動使用フィクスチャがこの場合の「最も明確な」メソッドであることに同意しません。動作します。そこにはたくさんの魔法があります、imo。
したがって、できることの1つは、リンターを爆発させず、TestCaseボイラープレートを必要としないことです。これは、グローバルと呼ばれるモジュールを作成することです。このモジュール内で、グローバルにしたいものの名前を{}またはNoneにスタブ化し、グローバルモジュールをテストにインポートします。次に、conftest.pyファイルで、py.testフックを使用して、必要に応じてグローバル変数を設定(またはリセット)します。これには、テストをビルドするときに使用するスタブと、実行時のテストの完全なデータを提供できるという利点があります。
たとえば、pytest_configure()
フックを使用して、py.testの起動時に辞書を設定できます。または、各テスト間でデータが初期状態であることを確認したい場合は、フィクスチャを自動使用して、各テストの前に既知の状態にグローバル変数を割り当てます。
# globals.py
my_data = {} # Create a stub for your variable
# test_module.py
import globals as gbl
def test_foo():
assert gbl.my_data['foo'] == 'bar' # The global is in the namespace when creating tests
# conftest.py
import globals as gbl
my_data = {'foo': 'bar'} # Create the master copy in conftest
@pytest.fixture(autouse=True)
def populate_globals():
gbl.my_data = my_data # Assign the master value to the global before each test
このアプローチのもう1つの利点は、グローバルモジュールで型ヒントを使用して、テストのグローバルオブジェクトでコード補完を行うことができることです。これはおそらく辞書には必要ありませんが、 webdriverなど)。 :)
すべてのテストで使用されるグローバルの大きな辞書を作成することは、おそらく悪い考えです。可能であれば、この種のことを避けるためにテストをリファクタリングすることをお勧めします。
そうは言っても、ここに私がそれをする方法があります:すべての関数のグローバル名前空間で辞書への参照を追加する autouseフィクスチャ を定義します。
ここにいくつかのコードがあります。すべて同じファイルにありますが、テストの最上位でconftest.py
にフィクスチャを移動できます。
import pytest
my_big_global = {'key': 'value'}
@pytest.fixture(autouse=True)
def myglobal(request):
request.function.func_globals['foo'] = my_big_global
def test_foo():
assert foo['key'] == 'value'
def test_bar():
assert foo['key'] == 'bar'
このコードを実行したときの出力は次のとおりです。
$ py.test test_global.py -vv
======================================= test session starts =======================================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 2 items
test_global.py:9: test_foo PASSED
test_global.py:12: test_bar FAILED
============================================ FAILURES =============================================
____________________________________________ test_bar _____________________________________________
def test_bar():
> assert foo['key'] == 'bar'
E assert 'value' == 'bar'
E - value
E + bar
test_global.py:13: AssertionError
=============================== 1 failed, 1 passed in 0.01 seconds ===============================
各関数オブジェクトにアクセスできないため、セッションスコープのフィクスチャを使用できないことに注意してください。このため、大きなグローバル辞書を一度定義し、それへの参照を使用するようにします。その割り当てステートメントで辞書を定義すると、毎回新しいコピーが作成されます。
最後に、このようなことはおそらく悪い考えです。でも幸運:)
私はまだキャッシュについて言及された答えがないことに驚いています:バージョン2.8以降、pytest
には強力なキャッシュメカニズムがあります。
@pytest.fixture(autouse=True)
def init_cache(request):
data = request.config.cache.get('my_data', None)
data = {'spam': 'eggs'}
request.config.cache.set('my_data', data)
組み込みのrequest
フィクスチャを介して、テストでデータ辞書にアクセスします。
def test_spam(request):
data = request.config.cache.get('my_data')
assert data['spam'] == 'eggs'
request.cache
の優れた点は、ディスク上に保持されるため、テストの実行間で共有できることです。これは、分散テスト(pytest-xdist
)を実行したり、生成された後に変更されない長時間実行されるデータ生成がある場合に便利です。
@pytest.fixture(autouse=True)
def generate_data(request):
data = request.config.cache.get('my_data', None)
if data is None:
data = long_running_generation_function()
request.config.cache.set('my_data', data)
これで、ディスク上のキャッシュを明示的にクリアしない限り、テストは異なるテスト実行で値を再計算する必要がなくなります。現在キャッシュにあるものを見てみましょう:
$ pytest --cache-show
...
my_data contains:
{'spam': 'eggs'}
--cache-clear
フラグを使用してテストを再実行し、キャッシュを削除して、データを強制的に再計算します。または、プロジェクトルートディレクトリの.pytest_cache
ディレクトリを削除します。
pytest
docsの関連セクション: キャッシュ:クロステスト実行状態での作業 。
グローバル変数をpytest_addoption
フック内のオプションとして追加できます。コマンドラインを検査せずに属性を決定する場合は、addoption
を使用して明示的に行うか、set_defaults
メソッドを使用できます。 docs
オプションが定義されたら、request.config.getoption
を使用してフィクスチャ内に貼り付けてから、明示的または自動使用でテストに渡すことができます。または、config
オブジェクト内のほとんどすべてのフックにオプションを渡すことができます。
#conftest.py
def pytest_addoption(parser):
parser.addoption("--my_global_var", default="foo")
parser.set_defaults(my_hidden_var="bar")
@pytest.fixture()
def my_hidden_var(request):
return request.config.getoption("my_hidden_var")
#test.py
def test_my_hidden_var(my_hidden_var):
assert my_hidden_var == "bar"