Skip to content

when @parametrize finds a fixture_ref in its argvalues, the parameter is not anymore accessible through request.getfixturevalue #146

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
TheCaffinatedDeveloper opened this issue Nov 14, 2020 · 7 comments
Labels
wontfix This will not be worked on

Comments

@TheCaffinatedDeveloper
Copy link

Hi again @smarie!

Trying to figure out how to maintain the return values from cases that use a fixture as their own fixture name.

Example

conftest.py

@pytest.fixture
def some_fixture():
       return 1

@pytest.fixture(scope='function', autouse=True)
def some_other_fixture(request):
       # ouput will contain test_some_test_important_value_other_important_value as the fixture name
       print('fixturenames: ' + str(request.node.fixturenames))
       # hoping for important_value and other_important_value to be listed as fixtures

def case_some_case(some_fixture):
      important_value = some_fixture
      other_important_value = 2
      return important_value, other_important_value

mock_test.py

@parametrize_with_cases("important_value, other_important_value", cases='.')
def test_some_test(important_value, other_important_value):
       # important_value and other_important_value are here no problem
       assert important_value == 1
       assert other_important_value == 2

expected: [request, ..., ..., important_value, other_important_value, ...]
actual: [request, ..., ..., test_some_test_important_value_other_important_value, ...]

Note: this only happens when I use a fixture on the case.

@TheCaffinatedDeveloper
Copy link
Author

I should note that I was able to use the follow to accomplish what I was looking for:

@fixture_plus
@parametrize_with_cases("important_value,other_important_value", cases='.')
def prepare_test_cases(important_value, other_important_value):
    return important_value, other_important_value

important_value, other_important_value = unpack_fixture("important_value,other_important_value", prepare_test_cases)

I didn't change anything in the case_ functions. While this works, it would be cool to have similar functionality for @parametrize_with_cases by having an option to prevent packing or union etc.

@smarie
Copy link
Owner

smarie commented Nov 15, 2020

Hi @TheCaffinatedDeveloper , I am not sure to understand what the actual issue is.
All fixture names are preserved. However additional new fixtures are created automatically behind the scenes by @parametrize when there is at least a fixture_ref in the parameters. This happens when @parametrize_with_cases finds a case that relies on a fixture: it creates a fixture for the case, and then creates a fixture_ref pointing to it in the generated @parametrize.

So that is why you have for example test_some_test_important_value_other_important_value in the list.

If you compare the lists you should see that no name disappeared, only new names appeared. Let me know if this is not the case.

@TheCaffinatedDeveloper
Copy link
Author

Hi @TheCaffinatedDeveloper , I am not sure to understand what the actual issue is.
All fixture names are preserved. However additional new fixtures are created automatically behind the scenes by @parametrize when there is at least a fixture_ref in the parameters. This happens when @parametrize_with_cases finds a case that relies on a fixture: it creates a fixture for the case, and then creates a fixture_ref pointing to it in the generated @parametrize.

So that is why you have for example test_some_test_important_value_other_important_value in the list.

If you compare the lists you should see that no name disappeared, only new names appeared. Let me know if this is not the case.

@smarie Thank you for your reply. That definitely makes sense. To clarify my example, if you print a list of fixtures using request.node.fixturenames the names do appear to be preserved here.

Even further, if you were use request.getfixturevalue('important_value') it would say that the fixture does not exist.

Again, this is only when a case_ is using a fixture_ref.

@TheCaffinatedDeveloper
Copy link
Author

@smarie I know you are busy so I created a repl to demonstrate the issue:
Example

@smarie
Copy link
Owner

smarie commented Nov 18, 2020

Thanks @TheCaffinatedDeveloper for this example ! I did not know about repl.it, quite cool :)

I copy the examples here for reproducibility

from pytest_cases import parametrize_with_cases

def case_without_fixture():
  important_value = 1
  other_important_value = 2
  return important_value, other_important_value 


@parametrize_with_cases("important_value,other_important_value", cases='.')
def test_case_without_fixture(request, important_value, other_important_value):
  # important_value and other_important_value are here no problem
  value = request.getfixturevalue('important_value').get()
  
  assert value == 1
  assert other_important_value == 2

and

from pytest_cases import parametrize_with_cases

def case_with_fixture(some_fixture):
  important_value = some_fixture
  other_important_value = 2
  return important_value, other_important_value

@parametrize_with_cases("important_value,other_important_value", cases='.')
def test_case_with_fixture(request, important_value, other_important_value):
  value = None
  try:
    value = request.getfixturevalue('important_value').get()
  except:
    print('Fixture not found :(')
  
  assert value == important_value
  assert important_value == 1
  assert other_important_value == 2

I think that there is a small misunderstanding here: important_value is not a fixture, this is a parameter. But since the pytest api is misleadingly named getfixturevalue it is quite normal to do the mistake :)
Ok I see the issue, and I'm afraid that this might be extremely difficult to fix. That being said, I'll have a look when I'm back to normal activity. Thanks !

@TheCaffinatedDeveloper
Copy link
Author

@smarie Thanks, glad you found REPL.it useful 👍

@smarie
Copy link
Owner

smarie commented Dec 16, 2020

Trying to reformulate this ticket in order to leave it open: when @parametrize finds a fixture_ref in its argvalues, the parameter is not anymore accessible through request.getfixturevalue.

Minimal example:

from pytest_cases import parametrize, fixture, fixture_ref

@parametrize("a", [1])
def test_without_fixture_ref(request, a):
    print(request._fixture_defs)
    assert request.getfixturevalue('a') == 1

@fixture
def some_fixture():
    return 1

@parametrize("a", [fixture_ref(some_fixture)])
def test_with_fixture_ref(request, a):
    print(request._fixture_defs)
    assert request.getfixturevalue('a') == 1

This is due to the fact that a does not exist as a parameter in the second case. Indeed @parametrize replaces test_with_fixture_ref with a wrapper function, depending on a newly generated fixture named test_with_fixture_ref_a. We can look at the console prints above to see it in request._fixture_defs.

So the second test is equivalent to

@fixture
def some_fixture():
    return 1

@fixture
def test_with_fixture_ref_a(some_fixture):
    return some_fixture

def test_with_fixture_ref(request, test_with_fixture_ref_a):
    a = test_with_fixture_ref_a
    print(request._fixture_defs)
    assert request.getfixturevalue('a') == 1

I'm afraid there is no simple solution to this problem... I suggest to close as "won't fix" except if you feel that this should be tackled. In that case we'll leave it open for community support

@smarie smarie changed the title cases with fixture change fixturenames when @parametrize finds a fixture_ref in its argvalues, the parameter is not anymore accessible through request.getfixturevalue Dec 16, 2020
@smarie smarie changed the title when @parametrize finds a fixture_ref in its argvalues, the parameter is not anymore accessible through request.getfixturevalue when @parametrize finds a fixture_ref in its argvalues, the parameter is not anymore accessible through request.getfixturevalue Dec 16, 2020
@smarie smarie added the wontfix This will not be worked on label Jan 25, 2021
@smarie smarie closed this as completed Jan 25, 2021
smarie pushed a commit that referenced this issue Jan 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants