Skip to content

Independent parameter #31

Closed
Closed

Description

@Sup3rGeo

Hi, this is a feature suggestion, which I believe is the missing piece of parametrization

We can define an individual parameter used for parametrization that is not either intrinsically tied to a fixture or test function like this:

@fixture(params=[1,2,3,4])
def my_parameter(request):
    return request.param

@fixture
def fixture_uses_param(my_parameter):
    pass

def test_uses_param(my_parameter, fixture_uses_param):
    pass

The example above is bad because we are using a fixture to mask what is really a parameter. But we can solve this by doing:

def parameter(values):
    @pytest.fixture(scope="session", params=params)
    def parameter_fixture(request):
        return request.param
    return parameter_fixture

and then the test becomes:

my_parameter = parameter([1,2,3,4])

@fixture
def fixture_uses_param(my_parameter):
    pass

def test_uses_param(my_parameter, fixture_uses_param):
    pass

And we can use many parameters to have a cartesian product, etc etc. This still has two problems though:

  • It does not use the string definition of arguments. In other words, maybe it would be preferred to have parameter("my_parameter", [1,2,3,4]) instead of my_parameter = parameter([1,2,3,4])
  • I cannot parametrize a pair of arguments like this. This is related to the previous bullet point as we would need the alternate syntax for this: parameter("my_parameter1, my_parameter2", [(1,2),(3,4)]).

So, the feature proposal would be to have this parametrization ability through the module body with the mentioned syntax:

parameter("my_parameter, my_other_parameter", [(1,1), (2,2), (3,3), (4,4)])

@fixture
def fixture_uses_param(my_parameter):
    pass

def test_uses_param(my_parameter, my_other_parameter, fixture_uses_param):
    pass

Is this even possible? I know very little about how parametrization works under the hood in pytest, so if you might be not interested in this feature, I would appreciate some pointers.

thanks!

Activity

  1. smarie commented on Mar 22, 2019

    @smarie
    Owner

    I am not sure that I understand what you wish to do here.

    Is this that you wish to reuse parameters for multiple tests ? Or that you dislike the @pytest.mark.parametrize syntax so much that you wish to create an alias ? ;)

  2. Sup3rGeo commented on Mar 22, 2019

    @Sup3rGeo
    Author

    Or that you dislike the @pytest.mark.parametrize syntax so much that you wish to create an alias ? ;)

    No no, I like parametrize, but it injects the parameter for the specific test or fixture it is decorating.

    Is this that you wish to reuse parameters for multiple tests ?

    That`s it, or reuse it in a fixture and a test, which is the first two code snippets I presented, which you can already do today. But what I can't do is have that for parametrizing a pair/triple/n-uple of parameters.

  3. smarie commented on Mar 22, 2019

    @smarie
    Owner

    I see. Well yes I guess that the answer to your need is indeed a "parameter fixture" as you show.

    We could imagine a param_fixture helper function (basically a renaming of your first parameter function above). But as you point out we would have to extend it to support n-tuples. This is relatively easy: we would simply have to create several fixtures depending on each other (whatever the order). I can give it a try next week, we'll see if that gets adopted :)

  4. smarie commented on Mar 25, 2019

    @smarie
    Owner

    I managed to implement it but in case of several parameter names, I had to create a "root" fixture above all parameters. Anyway it works as expected, I'll ship 1.5.0 so that you can give it a try.

    Here is an example:

    # create a single parameter fixture
    my_parameter = param_fixture("my_parameter", [1, 2, 3, 4])
    
    
    @pytest.fixture
    def fixture_uses_param(my_parameter):
        return my_parameter
    
    
    def test_uses_param(my_parameter, fixture_uses_param):
        # check that the parameter injected in both is the same
        assert my_parameter == fixture_uses_param
    
    
    # -----
    # create a 2-tuple parameter fixture
    arg1, arg2 = param_fixtures("arg1, arg2", [(1, 2), (3, 4)])
    
    
    @pytest.fixture
    def fixture_uses_param2(arg2):
        return arg2
    
    
    def test_uses_param2(arg1, arg2, fixture_uses_param2):
        # check that the parameter injected in both is the same
        assert arg2 == fixture_uses_param2
        assert arg1, arg2 in [(1, 2), (3, 4)]
  5. smarie commented on Mar 25, 2019

    @smarie
    Owner

    Note: may I kindly ask you to support these new features into the main pytest project (I saw that you opened a thread already) if they suit your needs ? Indeed it would be better for everyone I think, rather than keeping them here.

  6. Sup3rGeo commented on Mar 25, 2019

    @Sup3rGeo
    Author

    Thanks, I will check it out (and probably make an issue if I find anything wrong)!

    And sure I also believe this should eventually get into pytest itself, as many people are using this pattern of creating fixture parameters and this makes it more explicit.

  7. smarie commented on Mar 26, 2019

    @smarie
    Owner

    perfect! let me know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions