Pass a parameter to a fixture function
Update: Since this the accepted answer to this question and still gets upvoted sometimes, I should add an update. Although my original answer (below) was the only way to do this in older versions of pytest as others have noted pytest now supports indirect parametrization of fixtures. For example you can do something like this (via @imiric):
# test_parameterized_fixture.py
import pytest
class MyTester:
def __init__(self, x):
self.x = x
def dothis(self):
assert self.x
@pytest.fixture
def tester(request):
"""Create tester object"""
return MyTester(request.param)
class TestIt:
@pytest.mark.parametrize('tester', [True, False], indirect=['tester'])
def test_tc1(self, tester):
tester.dothis()
assert 1
$ pytest -v test_parameterized_fixture.py
================================================================================= test session starts =================================================================================
platform cygwin -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: .
collected 2 items
test_parameterized_fixture.py::TestIt::test_tc1[True] PASSED [ 50%]
test_parameterized_fixture.py::TestIt::test_tc1[False] FAILED
However, although this form of indirect parametrization is explicit, as @Yukihiko Shinoda points out it now supports a form of implicit indirect parametrization (though I couldn't find any obvious reference to this in the official docs):
# test_parameterized_fixture2.py
import pytest
class MyTester:
def __init__(self, x):
self.x = x
def dothis(self):
assert self.x
@pytest.fixture
def tester(tester_arg):
"""Create tester object"""
return MyTester(tester_arg)
class TestIt:
@pytest.mark.parametrize('tester_arg', [True, False])
def test_tc1(self, tester):
tester.dothis()
assert 1
$ pytest -v test_parameterized_fixture2.py
================================================================================= test session starts =================================================================================
platform cygwin -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: .
collected 2 items
test_parameterized_fixture2.py::TestIt::test_tc1[True] PASSED [ 50%]
test_parameterized_fixture2.py::TestIt::test_tc1[False] FAILED
I don't know exactly what are the semantics of this form, but it seems that pytest.mark.parametrize
recognizes that although the test_tc1
method does not take an argument named tester_arg
, the tester
fixture that it's using does, so it passes the parametrized argument on through the tester
fixture.
I had a similar problem--I have a fixture called test_package
, and I later wanted to be able to pass an optional argument to that fixture when running it in specific tests. For example:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(It doesn't matter for these purposes what the fixture does or what type of object the returned package
) is.
It would then be desirable to somehow use this fixture in a test function in such a way that I can also specify the version
argument to that fixture to use with that test. This is currently not possible, though might make a nice feature.
In the meantime it was easy enough to make my fixture simply return a function that does all the work the fixture previously did, but allows me to specify the version
argument:
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
Now I can use this in my test function like:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
and so on.
The OP's attempted solution was headed in the right direction, and as @hpk42's answer suggests, the MyTester.__init__
could just store off a reference to the request like:
class MyTester(object):
def __init__(self, request, arg=["var0", "var1"]):
self.request = request
self.arg = arg
# self.use_arg_to_init_logging_part()
def dothis(self):
print "this"
def dothat(self):
print "that"
Then use this to implement the fixture like:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
If desired the MyTester
class could be restructured a bit so that its .args
attribute can be updated after it has been created, to tweak the behavior for individual tests.
pytest fixture with argument
This works:
@pytest.fixture
def my_fixture(request):
print("fixture in")
yield request.param+1 # difference here !
print("fixture out")
@pytest.mark.parametrize("my_fixture",[1], indirect=True)
def test_myfixture(my_fixture):
print(my_fixture)
How to pass a parameter to a pytest fixture?
I was able to achieve what I wanted with fixture factories
@pytest.fixture
def foo(tmp_path):
def _foo(a: int, b: int = 2):
return a + b
return _foo
def test_args(tmp_path, foo):
bar = foo(a=1)
assert bar == 3
How to pass a fixture as param to another fixture
I found a solution that worked for me, thanks to this answer by Will.
It seems like you can just use request.getfixturevalue
to get the return value of the fixture instead of the function object. Here is the working code for this:
@pytest.fixture()
def foo():
return "foo"
@pytest.fixture()
def boo(foo):
return foo + "boo"
@pytest.fixture()
def bar(foo):
return foo + "bar"
@pytest.fixture(params=['boo', 'bar'], ids=["boo_fixture", "bar_fixture"])
def final_fixture(request):
return request.getfixturevalue(request.param)
def _test(final_fixture):
assert final_fixture.startswith('foo')
Here is the related doc: http://doc.pytest.org/en/latest/builtin.html#_pytest.fixtures.FixtureRequest.getfixturevalue
How to pass pytest fixture to the main function without adding it to parameters?
Your fixture does not replace the function get_settings
, it is just another implementation. What you need to do is to patch the implementation with your own, for example:
conftest.py
from unittest import mock
import pytest
@pytest.fixture
def get_settings():
with mock.patch("your_module.helpers.get_settings") as mocked_settings:
mocked_settings.return_value = Settings(
DEBUG=True,
TOKEN_KEY="SOME_FAKE_TOKEN_KEY",
TOKEN_PASSWORD='')
yield
Note that you have to mock the reference of get_settings
that is imported in your helpers
module, see where to patch.
Related Topics
Number of Days Between 2 Dates, Excluding Weekends
Find Longest Repetitive Sequence in a String
List of Dicts To/From Dict of Lists
Django Aggregation: Summation of Multiplication of Two Fields
Removing Unicode \U2026 Like Characters in a String in Python2.7
Should I Call Close() After Urllib.Urlopen()
How to Set Folder Permissions in Windows
What Does the Term "Broadcasting" Mean in Pandas Documentation
Asyncio.Sleep() VS Time.Sleep()
Python String 'Join' Is Faster () Than '+', But What's Wrong Here
How to Remove the Left Part of a String
Check If a File Is Open in Python
How to Remove an Element in Lxml