web-dev-qa-db-ja.com

py.testのすべてのテストのモジュール間で変数を共有する方法

複数のファイルの複数のクラスにあるpy.testによって実行される複数のテストがあります。

Py.testで使用されるすべてのファイルのすべてのクラスのすべてのメソッドで、大規模な辞書(複製したくない)を共有する最も簡単な方法は何ですか?

つまり、すべてのテストに対して「グローバル変数」を作成する必要があります。 py.test以外では、この変数を使用しないので、テスト対象のファイルに保存したくありません。私はpy.testのフィクスチャを頻繁に使用しましたが、これはこの必要性にとってはやり過ぎのようです。たぶんそれが唯一の方法ですか?

22
Trevor

更新: 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。ただし、フィクスチャはおそらくまだまだ優れています。

17
flub

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など)。 :)

13
user2859458

すべてのテストで使用されるグローバルの大きな辞書を作成することは、おそらく悪い考えです。可能であれば、この種のことを避けるためにテストをリファクタリングすることをお勧めします。

そうは言っても、ここに私がそれをする方法があります:すべての関数のグローバル名前空間で辞書への参照を追加する 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 ===============================

各関数オブジェクトにアクセスできないため、セッションスコープのフィクスチャを使用できないことに注意してください。このため、大きなグローバル辞書を一度定義し、それへの参照を使用するようにします。その割り当てステートメントで辞書を定義すると、毎回新しいコピーが作成されます。

最後に、このようなことはおそらく悪い考えです。でも幸運:)

8
Frank T

私はまだキャッシュについて言及された答えがないことに驚いています:バージョン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の関連セクション: キャッシュ:クロステスト実行状態での作業

5
hoefling

グローバル変数を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"
1
Kirill