Skip to content

Add possibility to pass parameter to the fixture from another fixture #1694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
OlegKuzovkov opened this issue Jul 2, 2016 · 12 comments
Closed
Labels
type: question general question, might be closed after 2 weeks of inactivity

Comments

@OlegKuzovkov
Copy link

Could you please implement possibility to pass parameter from one fixture to the parent one?
I have a complex fixture hierarchy in my test framework. I have some cases when i really need to have this feature.

Example:

@pytest.fixture(scope='session')
def fixture_1(request):
    return request.param

@pytest.fixture
def fixture_2(fixture_1): # Need to pass parameter here to fixture_1
    print (fixture_1)

So far I can pass parameter to the fixture from test using:

@pytest.mark.parametrize('fixture_1', ['parameter'], indirect=True)
def test_1(fixture_1):
     print (fixture_1)

Need to have exactly the same thing from fixture.

Thank you!

@nicoddemus nicoddemus added the type: question general question, might be closed after 2 weeks of inactivity label Feb 28, 2018
@nicoddemus
Copy link
Member

Currently there's no way to pass parameters to fixtures from within a test function or other fixtures, by that point the fixture function has already been called.

Usually the solution to this is to make a fixture return an object or function which you can call from within a test function and does what you need.

@pytest.fixture(scope='session')
def fixture_1(request):
    def do_it(param):
        # do something
    return do_it

@pytest.fixture
def fixture_2(fixture_1): # 
    result = fixture_1(some_param)

IOW the fixture becomes a factory function that you can call at any time.

Does that look reasonable to you?

@satishmovvar
Copy link

satishmovvar commented Apr 20, 2018

I do have a similar situation, where I need to pass a fixture as a params of another fixture. Is there any solution for me? Unfortunately I can't create my ValueProvider instance outside the fixture

class ValueProvider(object):
	def __init__(self):
		self.range = range(10)
	@property
	def values(self):
		return self.range

@pytest.fixture(scope="session")
def fxArgProvider(request):
	obj = ValueProvider()
	#Note: I have to create this object as part of fixture in my use case; 
	#		Can't make it as module variable
	return  obj

@pytest.mark.parametrize("value", fxArgProvider.values)
def test_rangeOfValues(value):
	# test logic
	assert value==""

@nicoddemus
Copy link
Member

@satishmovvar take a look at pytest-lazy-fixture.

@Sathisha-Movvar-Bose
Copy link

@nchammas thanks for the suggestion, but this still doesn't solve my problem. the lazy fixture returns an object with only one value for parametrize. I want to use a list of values from the fixture which is used as params in the test.

below code work with lazy fixture but that's not what I want.

@pytest.fixture(scope="class", params=[2,4,8])
def values(request):
    return request.param

@pytest.mark.parametrize('n_iter', [pytest.lazy_fixture("values")])
class Test_Class1:

instead I want something like below:

@pytest.fixture(scope="class")
def values(request):
    return [2,4,6]

@pytest.mark.parametrize('n_iter', pytest.lazy_fixture("values"))
class Test_Class1:

in which I get error "TypeError: 'LazyFixture' object is not iterable". I found an open question in StackOverflolw similar to my scenario -https://stackoverflow.com/questions/50482416/use-pytest-lazy-fixture-list-values-as-parameters-in-another-fixture

@nchammas
Copy link
Contributor

nchammas commented Jul 5, 2018

@sathishaMovvar - You pinged me but I think you meant to ping @nicoddemus instead.

@RonnyPfannschmidt
Copy link
Member

@sathishaMovvar currently this is simply impossible - parameterization happens before any fixture is ever made

@OlegKuzovkov
Copy link
Author

@RonnyPfannschmidt But what if on the parameterization stage we could define that parameter is another fixture, and retrieve its value only on the actual call assuming that it was previously executed and has a result already?
Just an idea, sorry.

This is how I actually solved my problem. I was passing only fixture name into another fixture as a parameter, and, using reflection, retrieved its the value on the call. It was kinda dirty, but it worked.

@RonnyPfannschmidt
Copy link
Member

@OlegKuzovkov at a work project we have a plugin providing parameter ids and actual values to parameterization in a controlled manner - there is no need to magically have some fixutures at collect time

@OlegKuzovkov
Copy link
Author

OlegKuzovkov commented Jul 6, 2018

@RonnyPfannschmidt Good, but at our working project we use fixtures to execute different pieces of logic, grab the output and use it further in tests/fixtures. Some of those fixtures are parametrized, and we are passing the values to those from the tests using undirect=True flag in parametrized decorator. At some point, we faced the scenario where we had to execute the fixture with certain parameters and pass the output object to another one.
And this is what the issue is about.

@RonnyPfannschmidt
Copy link
Member

that use-case is unsupported then ^^

@designerzim
Copy link

IOW the fixture becomes a factory function that you can call at any time.

Does that look reasonable to you?

That method removes a huge advantage of fixtures: assertions/exceptions from fixtures will result in a test error. Fixtures are a great place to put in sanity tests to make sure the the system under test is in a valid state, to separately validate test resources outside of the tests themselves. This improves analysis and allows fixtures to act as gatekeepers to prevent wasting time executing tests that will fail without special intervention (such as issues from a power outage, build failure, unplugged cables, or IP address change).

However, the nested function acts like a regular/test function and not a fixture. Most critically: assertions/exceptions get reported as failures, and thus mixed up with test results. For complex test systems, this wastes a lot of analysis time to discover which reported "Failure"(s) is actually an "Error."

@nicoddemus
Copy link
Member

@designerzim an alternative would be to use custom exceptions instead of assertions in that case. It would probably improve code readability because you can have an hierarchy of exceptions with various error conditions. Those exceptions would be an Error regardless if they executed in a fixture or test then.

Otherwise I believe we can close this discussion?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question general question, might be closed after 2 weeks of inactivity
Projects
None yet
Development

No branches or pull requests

7 participants