I've googled and read most of pytest documents but didn't find this topic.
I want to store runtime information(such as status code returned from server being tested) in some pytest item properites, to be used in reporting phase, particuarly add some column data in pytest-html.
Printing to stdout can accomplish similiar goal but I think not elegant nor efficient, since I need to regex extract from the captured text again.
I find item.stash maybe a good place to store such information, because it looks straightforward and strong typed. Currently below code works but I'm afraid it's not best practice.
Working but ugly:
# in cfgtest.py
status_code_key = pytest.StashKey[int]()
node_item_map = {}
def pytest_runtest_setup(item):
node_item_map[item.nodeid] = item
@pytest.fixture()
def current_item(request):
return node_item_map[request.node.nodeid]
# use this value in reporting
def pytest_runtest_makereport(item, call):
status_code = item.stash[status_code_key]
# in test_server.py
import pytest
import requests
@pytest.fixture(params=['example.com', 'google.com'], ids=["example", "google"])
def host(request):
return request.param
def test_status(host, current_item):
url = f'http://www.{host}'
status_code = requests.get(url).status_code
current_item.stash[status_code_key]=status_code
One drawbacks is, if the target value is deeply nested in functions calls, the fixture current_item
cannot be access easily either, unless pass the value along the calling stack.
def internal_methods_called_by_test(url):
status_code = requests.get(url).status_code
# if would be great if the item instance can be referenced here
Is any better way to write some auto used fixture that can accesse the item
instance more elegantly? of course, please give one example if possible.
Currently there's no answer yet, and I coincidentally came across pytest-current-test-environment-variable in pytest docs, and found solution to access the item anywhere.
def test_status(host):
# just to demonstrate non-test function
run_server(host)
def run_server(host):
url = f'http://www.{host}'
resp = requests.get(url)
status_code = resp.status_code
# env value is like test_attach.py::test_status[google] (call)
node_id = os.environ['PYTEST_CURRENT_TEST'].replace(' (call)', '')
current_item = node_item_map[node_id]
current_item.stash[status_code_key] = status_code
This solution is currently satisfying my needs, but still ugly, because I need to split string again, and document says
The contents of PYTEST_CURRENT_TEST is meant to be human readable and the actual format can be changed between releases (even bug fixes) so it shouldn’t be relied on for scripting or automation.
Better ideas are still welcome!