Reputation: 44345
In py.test
I need to dynamically define tests, depending on tests I defined in a file.
So what I was thinking is to define a fixture in conftest.py
that reads the file and returns a dictionary with the tests.
File tests.json
:
{
"test1": "text",
"test2": "42",
"test3": 1
}
I then define a fixture in conftest.py
to return the dictionary with the tests:
def pytest_addoption(parser):
parser.addoption(
"--tests",
default="tests.json",
)
@pytest.fixture
def mytests(request):
testfile = request.config.getoption("--tests")
with open(testfile) as f:
tests = json.load(f)
return tests
and then I can use a parametrized test as follows in test_pytest.py
:
@pytest.mark.parametrize("test_name", [(key) for key, value in mytests.items()])
def test1(test_name):
print(test_name)
which does not work as, at this point, py.test
does not seem to 'know' that mytests
is a fixture. I get an error
E NameError: name 'mytests' is not defined
How to handle this correctly? I just want to be able to either run all the test that are defined in the json file, or to be able to select a single test from it with the -k
option if py.test
.
How to do it?
Based on some comments given below I tried to implement something as follows:
@pytest.hookimpl
def pytest_generate_tests(metafunc):
if "myparam" in metafunc.fixturenames:
with open(metafunc.config.option.tests) as f:
tests = json.load(f)
# add parametrization for each fixture name
for name, value in tests.items():
print(name, value)
metafunc.parametrize("mparam", (name, value))
def test1(myparam):
print(myparam)
But with this I got an error
ERROR test_pytest.py - ValueError: duplicate 'myparam'
Upvotes: 0
Views: 683
Reputation: 16815
As mentioned in the comments, you cannot use a fixture in mark.parametrize
. Fixtures can only be used in test functions and other fixtures.
To have dynamic parametrization like in this case, you can implement the hook function pytest_generate_tests
:
@pytest.hookimpl
def pytest_generate_tests(metafunc):
if "test_name" in metafunc.fixturenames:
testfile = metafunc.config.getoption("--tests")
with open(testfile) as f:
tests = json.load(f)
metafunc.parametrize("test_name", tests.items())
def test1(test_name):
print(test_name)
This will parametrize all tests with a "test_name" argument (e.g. fixture) with the items in the config file.
Running this with the given json file will result in something like:
$ python -m pytest -s
...
collected 3 items
test_pytest.py ('test1', 'text')
.('test2', '42')
.('test3', 1)
.
Upvotes: 2