python-pytest-cases icon indicating copy to clipboard operation
python-pytest-cases copied to clipboard

[Major] Improve the fixture union engine to support hybrid param+fixture mode

Open smarie opened this issue 4 years ago • 2 comments
trafficstars

The latest developments about test ids uniformization, as well as #146 and https://github.com/pytest-dev/pytest/issues/8155, made me realize that maybe the fixture union engine could be extended to natively support hybrid param+fixture unions.

If this works this would have two benefits:

  • first, @parametrize would not have to generate a global union fixture for the parameters as of today, immediately solving #146
  • second, @parametrize would not have to generate one fixture per group of parameters, so in particular @parametrize_with_cases would probably be much more efficient (far less fixtures generated, only when a case requires a fixture)

However... it will probably be hard to do. A few things to do:

  • UnionFixtureAlternative.to_list_of_fixture_names will have to only return only the fixtures and not the parameters https://github.com/smarie/python-pytest-cases/blob/aeb72ef30fd71d8cb332d7d1d55b60159ebc198d/pytest_cases/plugin.py#L295 so that FixtureClosureNode._build_closure can understand https://github.com/smarie/python-pytest-cases/blob/aeb72ef30fd71d8cb332d7d1d55b60159ebc198d/pytest_cases/plugin.py#L246

  • modify the calls reactor behaviour when it receives a Union Param https://github.com/smarie/python-pytest-cases/blob/aeb72ef30fd71d8cb332d7d1d55b60159ebc198d/pytest_cases/plugin.py#L760 and when it processes it: https://github.com/smarie/python-pytest-cases/blob/aeb72ef30fd71d8cb332d7d1d55b60159ebc198d/pytest_cases/plugin.py#L834

  • finally checking how the ids in all the tests will evolve and how/if we should adapt idstyle

Not an easy ride but might be worth the shot in 2021

smarie avatar Dec 16 '20 20:12 smarie

After sleeping on this I think the right order would better be:

    1. @parametrize does not need to create a test wrapper anymore. It needs to stop creating ParamAlternatives and instead just pass the argvalues as is. All argvalues containing fixture_ref, possibly marked, possibly nested in tuples, etc., need to be replaced with an easier to use object for example ValueWithFixtureRefs, remembering if the fixture ref is used for the whole tuple or for parts of it (possibly several).
    1. in FixtureClosureNode._build_closure, we should check that the corresponding parameter still pops in the received list. There is a need to detect that this parameter is special (because it contains fixture_refs). For this, the argvalues are currently inspected with https://github.com/smarie/python-pytest-cases/blob/b0681bb12e479469d416da1ce5688ba5838b3d3e/pytest_cases/fixture_core1_unions.py#L15 . This should therefore be modified so that it returns true if at least one ValueWithFixtureRefs is detected in the list.
    1. In the pytest_runtest_setup hook, this special ValueWithFixtureRefs object will probably need to be resolved using request._getfixture (?). For this a convenience ValueWithFixtureRefs.resolve(self, request_or_item) method on the object seems appropriate. https://github.com/smarie/python-pytest-cases/blob/aeb72ef30fd71d8cb332d7d1d55b60159ebc198d/pytest_cases/plugin.py#L60

smarie avatar Dec 17 '20 11:12 smarie

Another way to say the above is "before I thought that fixture unions were the core and parametrize would reuse this, but we have to revert this pattern: a fixture union is "just" a parametrized fixture with only fixture_ref argvalues. So @parametrize should be the core mechanism.

Another thing we'll need to do in this refactoring, as discussed in #158, is to support parametrized lazy_value and lazy_value requiring fixtures. This would enable us to remove all the fixture-creating "tricks" in @parametrize_with_cases.

This plan becomes clearer and clearer, I'm optimistic for 2021 ! But as always, devil will be in the tiny details: custom ids, custom marks, custom fixture scopes, etc.

smarie avatar Dec 18 '20 13:12 smarie