[英]How to share global variables between tests?
我在 conftest.py 中有一個全局變量並在測試中使用它。 例如:
conftest.py
api_version = 'v25'
api_url = 'http://www.foobar.com/' + api_version
test_foo.py
from conftest import api_url
import requests
@pytest.fixture
def data():
return requests.request("GET", api_url)
test_bar(data):
assert data is not None
現在我希望能夠從 cmd 更改 api_version 以測試其他 api 版本。 所以我用以下方式修改了conftest.py:
conftest.py
api_url = None
def pytest_addoption(parser):
parser.addoption("--api_version", action="store", default="v25", help="By default: v25")
@pytest.fixture(autouse=True, scope='session')
def cmd_param(pytestconfig):
api_version = pytestconfig.getoption("--mobile_api_ver").lower()
global api_url
if api_version in ['v24', 'v25', 'v26', 'v27']:
api_url = 'http://www.foobar.com/' + api_version
else:
raise ValueError('Unknown api version: ' + api_version)
但這並不像我預期的那樣工作,因為所有導入都在夾具之前執行,並且 test_foo import api_url = None在cmd_param 夾具重新定義它之前。 然后我編寫 get_api_url 方法並從測試模塊調用它:
conftest.py
api_url = None
def pytest_addoption(parser):
parser.addoption("--api_version", action="store", default="v25", help="By default: v25")
@pytest.fixture(autouse=True, scope='session')
def cmd_param(pytestconfig):
api_version = pytestconfig.getoption("--mobile_api_ver").lower()
global api_url
if api_version in ['v24', 'v25', 'v26', 'v27']:
api_url = 'http://www.foobar.com/' + api_version
else:
raise ValueError('Unknown api version: ' + api_version)
def get_api_url():
return api_url
但現在我也被迫更改 test_foo.py:
test_foo.py
from conftest import get_api_url
import requests
@pytest.fixture
def data():
return requests.request("GET", get_api_url())
test_bar(data):
assert data is not None
它有效,但解決方案看起來很尷尬。 有沒有更優雅的方法來使用自定義 cmd 選項而不更改測試文件?
根據docs , pytest_namespace
已在 4.0 版中刪除:
可以使用pytest_configure
來共享全局變量。
示例:
import pytest
def pytest_configure():
pytest.my_symbol = MySymbol()
注意:pytest_namespace 現已棄用
pytest 提供了一種在會話中使用某些全局變量的方法。 這些變量也可以被夾具使用。
這些變量是通過 pytest 鈎子控制的。
import pytest
def pytest_namespace():
return {'my_global_variable': 0}
@pytest.fixture
def data():
pytest.my_global_variable = 100
def test(data):
print pytest.my_global_variable
我不會弄亂全局變量。 只需定義您的夾具以返回一個值並在您的測試中使用該夾具:類似於@milo 發布的內容,但要簡單得多。
您還定義了--api_version
CLI 選項,但在您的裝置中訪問了--mobile_api_ver
選項。 此外,您的測試只是檢查響應對象是否不是 None,它永遠不會是 None,因此即使響應為 404 狀態,assert 語句也將始終通過,請參閱內嵌注釋。
這是一些可以工作的代碼:
conftest.py 的內容
import pytest
def pytest_addoption(parser):
parser.addoption("--api_version", action="store", default="v25", help="By default: v25")
@pytest.fixture(scope='session')
def api_url(pytestconfig):
api_version = pytestconfig.getoption("--api_version").lower()
if api_version in ['v24', 'v25', 'v26', 'v27']:
return 'http://www.foobar.com/' + api_version
else:
raise ValueError('Unknown api version: ' + api_version)
test_foo.py 的內容
import pytest
import requests
@pytest.fixture
def data(api_url): # probably a good idea to rename your fixture to a api_response or change what fixture returns.
return requests.get(api_url)
def test_bar(data):
print(data.text)
# below you are not testing data, but merely checking that response object is not None
assert data is not None # this will always pass
# you probably want to test status code and response content
assert data.status_code == 200
assert data.json()
運行測試: pytest -vvv --api_version v24 test_foo.py
我只是嘗試在不完全更改您的代碼的情況下使其工作。 我希望它能給你一些想法。
在conftest.py
api_url_by_option = None
def pytest_addoption(parser):
parser.addoption("--api_version", action="store", default="v25", help="By default: v25")
@pytest.fixture(autouse=True, scope='session')
def cmd_param(pytestconfig):
api_version = pytestconfig.getoption("--mobile_api_ver").lower()
global api_url_by_option
if api_version in ['v24', 'v25', 'v26', 'v27']:
api_url_by_option = 'http://www.foobar.com/' + api_version
else:
raise ValueError('Unknown api version: ' + api_version)
@pytest.fixture:
def api_url():
return api_url_by_option
在test_foo.py
您不需要導入api_url
。 請注意,在api_url
從夾具conftest.py
在夾具數據使用
import requests
@pytest.fixture
def data(api_url):
return requests.request("GET", api_url)
test_bar(data):
assert data is not None
conftest.py 文件用作為整個目錄提供設備的一種方式。 在 conftest.py 中定義的 Fixture 可以被該包中的任何測試使用,而無需導入它們(pytest 會自動發現它們)。
https://docs.pytest.org/en/6.2.x/fixture.html#conftest-py-sharing-fixtures-across-multiple-files
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 中所做的:
class StoreStuffHere:
something_to_start_with = "value"
somethingnew = None
#if you want an empty class:
class StoreStuffHere:
pass
我在 test_sample.py 中做什么:
from conftest import StoreStuffHere
store_stuff_here = StoreStuffHere
#this will pass
def test_assert_value_stored():
store_stuff_here.somethingnew = 45
assert store_stuff_here.something_to_start_with == "value"
#this will pass
def test_assert_fresh_stored_value():
assert store_stuff_here.somethingnew == 45
這將適用於同一模塊中的所有測試。 如果您對跨測試模塊使用相同的“存儲”感興趣,請使用字典或命名元組而不是我使用的類。 為了確保在某些測試失敗時不會出現缺失值錯誤,請使用 None 初始化所有已知值。
您目前可以按照文檔中的說明直接使用 pytest 對象,但只能作為權宜之計:
import pytest
def pytest_configure():
pytest.my_symbol = MySymbol()
但請注意是否使用pytest_namespace
版本,因為它已被棄用:
使用命名空間的舊版本:
class MySymbol:
...
def pytest_namespace():
return {"my_symbol": MySymbol()}
只是想分享最適合我的模式,我覺得它簡單明了。
在conftest.py
我有:
import pytest
from types import SimpleNameSpace
# Temporary Storage
pytest.tmp = SimpleNameSpace()
@pytest.fixture(autouse=True, scope="class")
def set_tmp_cls():
pytest.tmp.cls = SimpleNameSpace()
@pytest.fixture(autouse=True, scope="module")
def set_tmp_mod():
pytest.tmp.mod = SimpleNameSpace()
然后在測試中使用時:
import pytest
from pytest import tmp
def test_foo():
tmp.cls.var = 1
我使用了這個 class。 真正簡單且可擴展以供以后的變量使用
class TestVars:
"""Class to save and use variables"""
def __init__(self) -> None:
self.variables = {}
def save_var(self, variable: dict):
self.variables.update(variable)
def get_var(self, key):
return self.variables[key]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.