pytest-dev / pytest-dev/pytest

Parametrize based on another parameter

Open
#4,050 6 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

topic: parametrize type: proposal
Dominant language
Python
Stars
14.5k
Forks
3.4k
Avg merge
2d 9h
Merged PRs (30d)
35

Description

Hi,

This feature is related to a concept I think that pytest is missing. Let's say I have this very simple test:

@pytest.mark.parametrize("param", [1,2,3])
def test(param):
    mysetupcode(param)
    myassertfunc(param)

Now, I want to refactor the setup as a fixture, but still have the same parametrization for both the test and the fixture. In that case, I end up having to create a fixture:

@pytest.fixture(params=[1,2,3])
def param():
    # This is not a real fixture because it does not run any code
    return request.param

@pytest.fixture
def mysetupcode(param):
    # ... setup code
    pass

def test(param, mysetupcode):
    pass

So basically the concept that pytest is missing is this param fixture that is not a real fixture as does not run any code, but is just a parameter broadcast entity that is different from parametrizing at the individual fixture/test level.

Another example where this would be useful, with some API suggestions:

datasetA = [data1_a, data2_a, data3_a]
datasetB = [data1_b]
datasetC = [data1_c, data2_c]


# HERE the concept missing. The following line is equivalent to:
# @pytest.fixture(params=[datasetA, datasetB])
# def dataset(request)
#     return request.param
# Also you can think as a pytest.mark.parametrize not tied to any function
pytest.parameterize('dataset', [datasetA, datasetB])

# Fixtures could use it just as well (as it is just like a fixture)
# Actually becomes another way to parametrize
@pytest.fixture
def fixture1(dataset):
    setup(dataset)
    pass

# tests can use this concept as well, as we would with fixtures
def test_one(dataset)

# Following line is almost as if we are parametrizing the parametrize
# So it will be doubly parametrized: 
# test_data[datasetA-data1_a]
# test_data[datasetA-data2_a]
# test_data[datasetA-data3_a]
# test_data[datasetB-data1_b]
# test_data[datasetC-data1_c]
# test_data[datasetC-data2_c]
@pytest.mark.parametrize('data', pytest.parameter('dataset')])
def test_data(data):
    #do test

This feature was discussed in
https://github.com/TvoroG/pytest-lazy-fixture/issues/25
https://github.com/pytest-dev/pytest/issues/349#issuecomment-339658616

I decided to open a new feature request because I believe it is a different use case/implementation than #349, although they might be related. The difference is that we don't need to worry about this that @nicoddemus mentioned:

Under the current design, pytest needs to generate all items during the collection stage. Your examples generate new items during the session testing stage (during fixture instantiation), which is not currently possible.

Because we don't need to run any code to have all the parameters in place at collection time.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation files or tests are named. Start by reviewing the proposed parameter-broadcast behavior and the linked discussions in pytest-lazy-fixture#25 and pytest#349, then determine how collection-time parameters should interact with fixtures and tests; done means a settled design and corresponding behavior for the examples described.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.