Skip to content
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

Independent parameter #31

Closed
Sup3rGeo opened this issue Mar 22, 2019 · 7 comments
Closed

Independent parameter #31

Sup3rGeo opened this issue Mar 22, 2019 · 7 comments

Comments

@Sup3rGeo
Copy link

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!

@smarie
Copy link
Owner

smarie commented Mar 22, 2019

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 ? ;)

@Sup3rGeo
Copy link
Author

Sup3rGeo commented Mar 22, 2019

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.

@smarie
Copy link
Owner

smarie commented Mar 22, 2019

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 :)

@smarie
Copy link
Owner

smarie commented Mar 25, 2019

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)]

@smarie smarie closed this as completed in e62df00 Mar 25, 2019
@smarie
Copy link
Owner

smarie commented Mar 25, 2019

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.

@Sup3rGeo
Copy link
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.

@smarie
Copy link
Owner

smarie commented Mar 26, 2019

perfect! let me know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants