Pytest: Is that possible to skip some of the fixture params on specific tests?

Created on 11 Jul 2020  路  4Comments  路  Source: pytest-dev/pytest

  • [x] a detailed description of the bug or suggestion
  • [ ] output of pip list from the virtual environment you are using
  • [ ] pytest and operating system versions
  • [x] minimal example if possible

Related = https://github.com/taichi-dev/taichi/issues/1458

Sometimes it's useful to skip some params in fixture for some specific test.
I know that using pytest.param(..., pytest.mark.skip) solve the problem, but it will skip this param for all the test.

For example:

import pytest
import mylib
import math

@pytest.fixture(params=[-2, -1, 0, 1, 2, 3, 4])
def operand(request):
    x = request.param
    # my project needs to do some special treatment on `x` here,
    # so simply `pytest.parametrize` with a list could not meet our need
    x = mylib.Variable(x)
    yield x

def test_abs(operand):  # test against all numbers
    assert mylib.abs(operand) == abs(operand)


def test_sqrt(operand):  # test against non-negative numbers
    if operand < 0:  # <- how do I skip `-2` and `-1` gracefully with out `SKIPPED`?
        pytest.skip()
    assert mylib.sqrt(operand) == math.sqrt(operand)

What we want is:

import pytest
import mylib
import math

@pytest.fixture(params=[-2, -1, 0, 1, 2, 3, 4])
def operand(request):
    x = request.param
    # my project needs to do some special treatment on `x` here,
    # so simply `pytest.parametrize` with a list could not meet our need
    x = mylib.Variable(x)
    yield x

def test_abs(operand):  # test against all numbers
    assert mylib.abs(operand) == abs(operand)


@pytest.mark.operand(skip_negative=True)
def test_sqrt(operand):  # test against non-negative numbers
    assert mylib.sqrt(operand) == math.sqrt(operand)
question

Most helpful comment

you can access markers in fixtures via request, try this on for size!

import pytest
import math

class Variable:
    def __init__(self, x):
        self.x = x

    def __index__(self):
        return self.x

    def __abs__(self):
        return abs(self.x)


@pytest.fixture(params=[-2, -1, 0, 1, 2, 3, 4])
def operand(request):
    x = request.param

    marker = request.node.get_closest_marker('operand')
    if marker and marker.kwargs.get('skip_negative', False) and x < 0:
        raise pytest.skip('skipping negative operand as requested')

    # my project needs to do some special treatment on `x` here,
    # so simply `pytest.parametrize` with a list could not meet our need
    x = Variable(x)
    yield x


def test_abs(operand):  # test against all numbers
    assert abs(operand) == abs(operand)


@pytest.mark.operand(skip_negative=True)
def test_sqrt(operand):  # test against non-negative numbers
    assert math.sqrt(operand) == math.sqrt(operand)
$ pytest t.py -vv -ra
============================= test session starts ==============================
platform linux -- Python 3.8.2, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 -- /tmp/z/venv/bin/python
cachedir: .pytest_cache
rootdir: /tmp/z
collected 14 items                                                             

t.py::test_abs[-2] PASSED                                                [  7%]
t.py::test_abs[-1] PASSED                                                [ 14%]
t.py::test_abs[0] PASSED                                                 [ 21%]
t.py::test_abs[1] PASSED                                                 [ 28%]
t.py::test_abs[2] PASSED                                                 [ 35%]
t.py::test_abs[3] PASSED                                                 [ 42%]
t.py::test_abs[4] PASSED                                                 [ 50%]
t.py::test_sqrt[-2] SKIPPED                                              [ 57%]
t.py::test_sqrt[-1] SKIPPED                                              [ 64%]
t.py::test_sqrt[0] PASSED                                                [ 71%]
t.py::test_sqrt[1] PASSED                                                [ 78%]
t.py::test_sqrt[2] PASSED                                                [ 85%]
t.py::test_sqrt[3] PASSED                                                [ 92%]
t.py::test_sqrt[4] PASSED                                                [100%]

=============================== warnings summary ===============================
t.py:33
  /tmp/z/t.py:33: PytestUnknownMarkWarning: Unknown pytest.mark.operand - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
    @pytest.mark.operand(skip_negative=True)

-- Docs: https://docs.pytest.org/en/latest/warnings.html
=========================== short test summary info ============================
SKIPPED [2] /tmp/z/t.py:21: skipping negative operand as requested
=================== 12 passed, 2 skipped, 1 warning in 0.02s ===================

All 4 comments

you can access markers in fixtures via request, try this on for size!

import pytest
import math

class Variable:
    def __init__(self, x):
        self.x = x

    def __index__(self):
        return self.x

    def __abs__(self):
        return abs(self.x)


@pytest.fixture(params=[-2, -1, 0, 1, 2, 3, 4])
def operand(request):
    x = request.param

    marker = request.node.get_closest_marker('operand')
    if marker and marker.kwargs.get('skip_negative', False) and x < 0:
        raise pytest.skip('skipping negative operand as requested')

    # my project needs to do some special treatment on `x` here,
    # so simply `pytest.parametrize` with a list could not meet our need
    x = Variable(x)
    yield x


def test_abs(operand):  # test against all numbers
    assert abs(operand) == abs(operand)


@pytest.mark.operand(skip_negative=True)
def test_sqrt(operand):  # test against non-negative numbers
    assert math.sqrt(operand) == math.sqrt(operand)
$ pytest t.py -vv -ra
============================= test session starts ==============================
platform linux -- Python 3.8.2, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 -- /tmp/z/venv/bin/python
cachedir: .pytest_cache
rootdir: /tmp/z
collected 14 items                                                             

t.py::test_abs[-2] PASSED                                                [  7%]
t.py::test_abs[-1] PASSED                                                [ 14%]
t.py::test_abs[0] PASSED                                                 [ 21%]
t.py::test_abs[1] PASSED                                                 [ 28%]
t.py::test_abs[2] PASSED                                                 [ 35%]
t.py::test_abs[3] PASSED                                                 [ 42%]
t.py::test_abs[4] PASSED                                                 [ 50%]
t.py::test_sqrt[-2] SKIPPED                                              [ 57%]
t.py::test_sqrt[-1] SKIPPED                                              [ 64%]
t.py::test_sqrt[0] PASSED                                                [ 71%]
t.py::test_sqrt[1] PASSED                                                [ 78%]
t.py::test_sqrt[2] PASSED                                                [ 85%]
t.py::test_sqrt[3] PASSED                                                [ 92%]
t.py::test_sqrt[4] PASSED                                                [100%]

=============================== warnings summary ===============================
t.py:33
  /tmp/z/t.py:33: PytestUnknownMarkWarning: Unknown pytest.mark.operand - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
    @pytest.mark.operand(skip_negative=True)

-- Docs: https://docs.pytest.org/en/latest/warnings.html
=========================== short test summary info ============================
SKIPPED [2] /tmp/z/t.py:21: skipping negative operand as requested
=================== 12 passed, 2 skipped, 1 warning in 0.02s ===================

Cool! Thank for your quick response! I know how to do now, sorry about disturbing you with this simple question :heart:

no problem! this wasn't that simple fwiw -- took me a good 15-20 minutes to get that example working :)

FWIW I also added something explaining this technique to the docs recently: https://docs.pytest.org/en/latest/fixture.html#using-markers-to-pass-data-to-fixtures

Was this page helpful?
0 / 5 - 0 ratings