Reputation: 667
I have to a test a scenario where one parameter is dependent on other. I tried using the pytest hook pytest_generate_test
but i'm not sure how to pass a retrieve the value in hook which is parametrized in the test.
import pytest
import logging
logger = logging.getLogger(__name__)
apps = ['app1', 'app2', 'app3']
def pytest_generate_tests(metafunc):
common_services = ['dns', 'dhcp']
service = apps[0]
common_services.append(service)
if "total_services" in metafunc.fixturenames:
metafunc.parametrize("total_services", common_services)
@pytest.fixture()
def total_services(request):
return request.param
@pytest.mark.parametrize("app", apps)
def test_example(app, total_services):
logging.info(f"App: {app}, ServiceName: {total_services}")
Output:
============================= test session starts ==============================
platform darwin -- Python 3.11.7, pytest-8.0.2, pluggy-1.4.0
rootdir: /private/tmp/test/tests
collected 9 items
test_example.py::test_example[dns-app1]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app1, ServiceName: dns
PASSED [ 11%]
test_example.py::test_example[dns-app2]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app2, ServiceName: dns
PASSED [ 22%]
test_example.py::test_example[dns-app3]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app3, ServiceName: dns
PASSED [ 33%]
test_example.py::test_example[dhcp-app1]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app1, ServiceName: dhcp
PASSED [ 44%]
test_example.py::test_example[dhcp-app2]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app2, ServiceName: dhcp
PASSED [ 55%]
test_example.py::test_example[dhcp-app3]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app3, ServiceName: dhcp
PASSED [ 66%]
test_example.py::test_example[app1-app1]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app1, ServiceName: app1
PASSED [ 77%]
test_example.py::test_example[app1-app2]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app2, ServiceName: app1
PASSED [ 88%]
test_example.py::test_example[app1-app3]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app3, ServiceName: app1
PASSED [100%]
============================== 9 passed in 0.01s ===============================
Expected output:
============================= test session starts ==============================
platform darwin -- Python 3.11.7, pytest-8.0.2, pluggy-1.4.0
rootdir: /private/tmp/test/tests
collected 9 items
test_example.py::test_example[dns-app1]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app1, ServiceName: dns
PASSED [ 11%]
test_example.py::test_example[dns-app2]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app2, ServiceName: dns
PASSED [ 22%]
test_example.py::test_example[dns-app3]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app3, ServiceName: dns
PASSED [ 33%]
test_example.py::test_example[dhcp-app1]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app1, ServiceName: dhcp
PASSED [ 44%]
test_example.py::test_example[dhcp-app2]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app2, ServiceName: dhcp
PASSED [ 55%]
test_example.py::test_example[dhcp-app3]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app3, ServiceName: dhcp
PASSED [ 66%]
test_example.py::test_example[app1-app1]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app1, ServiceName: app1
PASSED [ 77%]
test_example.py::test_example[app1-app2]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app2, ServiceName: app2
PASSED [ 88%]
test_example.py::test_example[app1-app3]
-------------------------------- live log call ---------------------------------
INFO root:test_example.py:21 App: app3, ServiceName: app3
PASSED [100%]
============================== 9 passed in 0.01s ===============================
I know I have hard coded to get the first element of the list service = apps[0]
i'm not sure how can we get the parameter passed in test can be retrieved in pytest_generate_tests
To keep explain it in simple way
from itertools import product
apps = ['app1', 'app2', 'app3']
def cartesian_product(app, common_servcies):
return list(product(app, common_servcies))
for app in apps:
common_services = ['dns', 'dhcp']
common_services.append(app)
print(cartesian_product([app], common_services))
Output:
$ python3 test_example2.py
[('app1', 'dns'), ('app1', 'dhcp'), ('app1', 'app1')]
[('app2', 'dns'), ('app2', 'dhcp'), ('app2', 'app2')]
[('app3', 'dns'), ('app3', 'dhcp'), ('app3', 'app3')]
Upvotes: 0
Views: 64
Reputation: 8654
Unless I missed some point in your question and all you want is a slightly odd product that you have already created in your mock example, then you should IMHO just use it as a helper function to generate the parameters for the parametrize
decorator:
import logging
from itertools import product
import pytest
def app_service_product(apps, common_services):
return list(product(apps, common_services)) + [[a, a] for a in apps]
@pytest.mark.parametrize(
"app, service",
app_service_product(["app1", "app2", "app3"], ["dns", "dhcp"]),
)
def test_example(app, service):
logging.info(f"App: {app}, ServiceName: {service}")
Upvotes: 1
Reputation: 40783
You almost solved your own problem. Here is one way to do it:
import itertools
import logging
import pytest
SERVICES_AND_APPS = []
for app in ["app1", "app2", "app3"]:
services = ["dns", "dhcp"] + [app]
SERVICES_AND_APPS.extend(itertools.product(services, [app]))
# BEGIN sort
def custom_key(service_and_app):
"""Ensure sort order of dns, dhcp, app1, app2, app3."""
custom_order = {
"dns": "a1",
"dhcp": "a2",
}
service, app = service_and_app
return custom_order.get(service, service), app
SERVICES_AND_APPS.sort(key=custom_key)
# END sort
@pytest.mark.parametrize("service,app", SERVICES_AND_APPS)
def test_example(service, app):
logging.info("app=%r, service=%r", app, service)
Notes
BEGIN sort
and END sort
ensures the order. If you don't care about the order (in general, you should not), then you can delete that part, which makes the script simpler to understand and shorter.custom_order
translate dns
to a1
, dhcp
to a2
, which ensure the order you are looking for.Upvotes: 0