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

Add a helper to return the names of parametrized test instances #9

Open
somnambWl opened this issue Aug 10, 2017 · 7 comments · May be fixed by #43
Open

Add a helper to return the names of parametrized test instances #9

somnambWl opened this issue Aug 10, 2017 · 7 comments · May be fixed by #43
Labels
enhancement New feature or request

Comments

@somnambWl
Copy link

Is there a way how can I mark parametrized test so that second, dependent, test will run only if first test passed on all parameters?

import pytest
import pytest_dependency

@pytest.mark.parametrize("x", [(True),(True)])
@pytest.mark.dependency()
def test_a(x):
    if x:
        pass
    else:
        assert 0

@pytest.mark.dependency(depends=["test_a"])
def test_b():
    pass

I know that I can mark each parameter, but this would be easier if the test should pass on all parameters and there is a lot of them.

Now this passes on first two tests (i.e. test_a) and second (test_b) is skipped.

@somnambWl somnambWl changed the title Parametrized test dependency - pass if all passed on all parameters Parametrized test dependency - pass if all passed all parameters Aug 10, 2017
@somnambWl somnambWl changed the title Parametrized test dependency - pass if all passed all parameters Parametrized test dependency - pass if passed on all parameters Aug 10, 2017
@RKrahl
Copy link
Owner

RKrahl commented Aug 13, 2017

There is no direct way to depend on all parameterized test instances of one test for the moment. What you can do is to collect all parameter values in a list variable and then construct the list of the names of the test instances from this list. Like this:

import pytest

paramvalues = [True, False]

@pytest.mark.parametrize("x", paramvalues)
@pytest.mark.dependency()
def test_a(x):
    if x:
        pass
    else:
        assert False

@pytest.mark.dependency(depends=["test_a[%s]" % str(v) for v in paramvalues])
def test_b():
    pass

Would that be sufficient for your use case?

@RKrahl RKrahl added the enhancement New feature or request label Aug 13, 2017
@RKrahl
Copy link
Owner

RKrahl commented Aug 13, 2017

@somnambWl, I need to add another remark on your example: you pass the same parameter value True twice to your test_a. Was this intended? This makes things a little bit more complicated, because pytest disambiguates the test names by prepending an index to the parameter value in this case. So the more complete solution that also works for non-unique parameter values would look like:

import pytest

def instances(name, params):
    if len(set(params)) == len(params):
        return ["%s[%s]" % (name, str(v)) for v in params]
    else:
        return ["%s[%d%s]" % (name, v[0], str(v[1])) for v in enumerate(params)]

paramvalues = [True, True]

@pytest.mark.parametrize("x", paramvalues)
@pytest.mark.dependency()
def test_a(x):
    if x:
        pass
    else:
        assert False

@pytest.mark.dependency(depends=instances("test_a", paramvalues))
def test_b():
    pass

On the other hand, I'm not sure if there are use cases where it actually makes sense to pass the same parameter value more the once to the same test.

@somnambWl
Copy link
Author

somnambWl commented Aug 15, 2017

Passing same value twice was not intended I just wanted first test to pass twice.

For me and for now, your workaround is sufficient, thank you :)

I am using list of strings as parameter, but with

pytest -v

I can see names of tests which pytest uses and adjust your solution.

@RKrahl
Copy link
Owner

RKrahl commented Aug 20, 2017

As a conclusion, I'm considering to add a helper function get_param_instances(test_name) that takes the name of a test as argument and returns a list of strings with the names of the instances for a parametrized test. If this is done, the solution above would look like:

import pytest
from pytest_dependency import get_param_instances

@pytest.mark.parametrize("x", [True, True])
@pytest.mark.dependency()
def test_a(x):
    if x:
        pass
    else:
        assert False

@pytest.mark.dependency(depends=get_param_instances("test_a"))
def test_b():
    pass

The benefit would be that you don't need to know how the test instances are named internally in pytest, you don't need to care about indexing in the case of double values in the parameters, and you don't need to store the parameter values.

The problem is that this helper function would need to get the instance names from the internal data structures of pytest and for the moment, I have no idea where and how these are stored. The documentation on the internal data structures in pytest is … sparse.

Note however that this Issue does not have high priority and might not make it into the next release version.

@RKrahl RKrahl changed the title Parametrized test dependency - pass if passed on all parameters Add a helper to return the names of parametrized test instances Aug 20, 2017
RKrahl added a commit that referenced this issue Aug 27, 2017
@JoeSc
Copy link
Contributor

JoeSc commented Feb 23, 2018

How about something like
JoeSc@79fce26

The change needed to the original post would be adding a "*" after test_a so it would look like

@pytest.mark.dependency(depends=["test_a*"])
def test_b():
    pass

@RKrahl
Copy link
Owner

RKrahl commented Feb 25, 2018

It suffers from the same consistency issue as the proposal in #19. Consider:

import pytest

def instances(name, params):
    def vstr(val):
        if isinstance(val, (list, tuple)):
            return "-".join([str(v) for v in val])
        else:
            return str(val)
    return ["%s[%s]" % (name, vstr(v)) for v in params]


@pytest.mark.parametrize("x,y", [
    pytest.mark.dependency()((0,0)),
    pytest.mark.dependency()(pytest.mark.xfail((0,1))),
    pytest.mark.dependency()((1,0)),
    pytest.mark.dependency()((1,1))
])
def test_a(x,y):
    assert y <= x

@pytest.mark.dependency(depends=instances("test_a", [(0,0),(0,1),(1,0),(1,1)]))
def test_b():
    pass

Here test_b will be skipped because it depends on test_a[0-1] which fails. This will also work if you run the test with python -m pytest 'test.py::test_a[1-0]' 'test.py::test_a[1-1]' 'test.py::test_b'. If we follow your suggestion and keep the same invocation of pytest, the dependency will implicitly be reduced to the tests listed in the command line, ["test_a[1-0]" "test_a[1-1]"] in this case, so that test_b will not be skipped.

@GalOz666
Copy link

GalOz666 commented Mar 8, 2019

the get_param_instances function would greatly help my project.

I believe the documentation now is better w/ regards to hooks. I will try to take a look myself.

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

Successfully merging a pull request may close this issue.

4 participants