He heredado un código que implementa pytest.mark.skipif para algunas pruebas. Al leer los documentos de Pytest, soy consciente de que puedo agregar condiciones, posiblemente verificar las variables de entorno o usar funciones más avanzadas de pytest.mark para controlar grupos de pruebas juntas. Desafortunadamente, nada en los documentos hasta ahora parece resolver mi problema.

Estoy buscando simplemente desactivar cualquier omisión de prueba, pero sin modificar ningún código fuente de las pruebas. Solo quiero ejecutar pytest en un modo en el que no se respete ningún indicador de omisión de prueba. ¿Existe tal solución con pytest?

4
ely 10 may. 2019 a las 16:20

3 respuestas

Una solución fácil es hacer un parche de mono pytest.mark.skipif en tu conftest.py:

import pytest

old_skipif = pytest.mark.skipif

def custom_skipif(*args, **kwargs):
    return old_skipif(False, reason='disabling skipif')

pytest.mark.skipif = custom_skipif
1
sanyash 11 may. 2019 a las 23:23

Una solución alternativa para ignorar las marcas de omisión es eliminarlas mediante programación. Cree un conftest.py con el siguiente contenido:

def pytest_collection_modifyitems(items):
    for item in items:
        for node in reversed(item.listchain()):
            node.own_markers = [m for m in node.own_markers if m.name not in ('skip', 'skipif')]

Sin embargo, esto interfiere con los elementos internos pytest y puede romperse fácilmente en las actualizaciones pytest; la forma correcta de ignorar los saltos debería ser definir su mecanismo de salto personalizado, por ejemplo:

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    mark = item.get_closest_marker(name='myskip')
    if mark:
        condition = next(iter(mark.args), True)
        reason = mark.kwargs.get('reason', 'custom skipping mechanism')
        item.add_marker(pytest.mark.skipif(not os.getenv('PYTEST_RUN_FORCE_SKIPS', False) and condition, reason=reason), append=False)

Anote las pruebas con @pytest.mark.myskip en lugar de @pytest.mark.skip y @pytest.mark.myskip(condition, reason) en lugar de @pytest.mark.skipif(condition, reason):

@pytest.mark.myskip
def test_skip():
    assert True


@pytest.mark.myskip(1 == 1, reason='my skip')
def test_skipif():
    assert True

En una ejecución regular, myskip se comportará de la misma manera que pytest.mark.skip / pytest.mark.skipif. La configuración PYTEST_RUN_FORCE_SKIPS lo deshabilitará:

$ PYTEST_RUN_FORCE_SKIPS=1 pytest -v
...
test_spam.py::test_skip PASSED
test_spam.py::test_skipif PASSED
...

Por supuesto, no debes usar pytest.mark.skip / pytest.mark.skipif ya que no serán influenciados por la PYTEST_RUN_FORCE_SKIPS env var.

1
sanyash 11 may. 2019 a las 23:25

Ok, la implementación no permite esto con cero modificaciones. Necesitarás un marcador personalizado. Agregue lo siguiente a su conftest.py y luego cambie todas las marcas skipif a custom_skipif. Use pytest --no-skips.

import pytest
from _pytest.mark.evaluate import MarkEvaluator

def pytest_addoption(parser):
    parser.addoption(
        "--no-skips", action="store_true", default=False, help="disable custom_skip marks"
    )

@hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    if item.config.getoption('--no-skips'):
        return

    # Check if skip or skipif are specified as pytest marks
    item._skipped_by_mark = False
    eval_skipif = MarkEvaluator(item, "custom_skipif")
    if eval_skipif.istrue():
        item._skipped_by_mark = True
        pytest.skip(eval_skipif.getexplanation())

    for skip_info in item.iter_markers(name="custom_skip"):
        item._skipped_by_mark = True
        if "reason" in skip_info.kwargs:
            pytest.skip(skip_info.kwargs["reason"])
        elif skip_info.args:
            pytest.skip(skip_info.args[0])
        else:
            pytest.skip("unconditional skip")

    item._evalxfail = MarkEvaluator(item, "xfail")
    check_xfail_no_run(item)

La implementación se copia y modifica desde pytest en skipping.py.

1
soundstripe 10 may. 2019 a las 17:32