Solución:
Los documentos describen exactamente su problema: https://docs.pytest.org/en/latest/example/simple.html#control-skipping-of-tests-according-to-command-line-option. Copiando desde allí:
Aquí hay un archivo conftest.py que agrega una opción de línea de comando –runslow para controlar la omisión de las pruebas marcadas con pytest.mark.slow:
# content of conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption(
"--runslow", action="store_true", default=False, help="run slow tests"
)
def pytest_collection_modifyitems(config, items):
if config.getoption("--runslow"):
# --runslow given in cli: do not skip slow tests
return
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
for item in items:
if "slow" in item.keywords:
item.add_marker(skip_slow)
Ahora podemos escribir un módulo de prueba como este:
# content of test_module.py
import pytest
def test_func_fast():
pass
@pytest.mark.slow
def test_func_slow():
pass
Hay un par de formas de manejar esto, pero repasaré dos enfoques comunes que he visto en las líneas base de Python.
1) Separe sus pruebas colocando las pruebas “opcionales” en otro directorio.
No estoy seguro de cómo se ve el diseño de su proyecto, pero puede hacer algo como esto (solo el directorio de prueba es importante, el resto es solo un diseño de ejemplo de juguete):
README.md
setup.py
requirements.txt
test/
unit/
test_something.py
test_something_else.py
integration/
test_optional.py
application/
__init__.py
some_module.py
Luego, cuando invoca pytest, lo invoca haciendo pytest test/unit
si quieres correr solo las pruebas unitarias (es decir, solo test_something*.py
archivos), o pytest test/integration
si quieres correr solo las pruebas de integración (es decir, solo test_optional.py
), o pytest test
si quieres correr todos los exámenes. Entonces, de forma predeterminada, puede ejecutar pytest test/unit
.
Recomiendo envolver estas llamadas en algún tipo de script. yo prefiero make
ya que es potente para este tipo de envoltura. Entonces puedes decir make test
y solo ejecuta su conjunto de pruebas predeterminado (rápido), o make test_all
y ejecutará todas las pruebas (que pueden ser lentas o no).
Ejemplo de Makefile con el que podrías envolver:
.PHONY: all clean install test test_int test_all uninstall
all: install
clean:
rm -rf build
rm -rf dist
rm -rf *.egg-info
install:
python setup.py install
test: install
pytest -v -s test/unit
test_int: install
pytest -v -s test/integration
test_all: install
pytest -v -s test
uninstall:
pip uninstall app_name
2) Marque sus pruebas con prudencia con el @pytest.mark.skipif
decorador, pero use una variable de entorno como desencadenante
No me gusta tanto esta solución, me parece un poco fortuita (es difícil saber qué conjunto de pruebas se están ejecutando en cualquier pytest
correr). Sin embargo, lo que puede hacer es definir una variable de entorno y luego conectar esa variable de entorno al módulo para detectar si desea ejecutar todas sus pruebas. Las variables de entorno dependen del shell, pero pretenderé que tiene un entorno bash, ya que es un shell popular.
Podrías hacerlo export TEST_LEVEL="unit"
solo para pruebas unitarias rápidas (por lo que este sería el predeterminado), o export TEST_LEVEL="all"
para todas tus pruebas. Luego, en sus archivos de prueba, puede hacer lo que originalmente intentaba hacer así:
import os
...
@pytest.mark.skipif(os.environ["TEST_LEVEL"] == "unit")
def test_scrape_website():
...
Nota: Nombrar los niveles de prueba “unidad” e “integración” es irrelevante. Puedes nombrarlos como quieras. También puede tener muchos niveles (como pruebas nocturnas o pruebas de rendimiento).
Además, creo que la opción 1 es la mejor manera de hacerlo, ya que no solo permite claramente la separación de las pruebas, sino que también puede agregar semántica y claridad a lo que significan y representan las pruebas. Pero no existe una “talla única” en el software, tendrá que decidir qué enfoque le gusta en función de sus circunstancias particulares.
HTH!
Una solución muy sencilla es utilizar el -k
argumento. Puedes usar el -k
parámetro para anular la selección de determinadas pruebas. -k
intenta hacer coincidir su argumento con cualquier parte del nombre o marcadores de las pruebas.Puede invertir la coincidencia utilizando not
(también puede usar los operadores booleanos and
y or
). Por lo tanto -k 'not slow'
omite las pruebas que tienen “lento” en el nombre, tiene un marcador con “lento” en el nombre, o cuyo nombre de clase / módulo contiene “lento”.
Por ejemplo, dado este archivo:
import pytest
def test_true():
assert True
@pytest.mark.slow
def test_long():
assert False
def test_slow():
assert False
Cuando corres:
pytest -k 'not slow'
Produce algo como: (tenga en cuenta que ambas pruebas fallidas se omitieron porque coincidían con el filtro)
============================= test session starts =============================
platform win32 -- Python 3.5.1, pytest-3.4.0, py-1.5.2, pluggy-0.6.0
rootdir: c:UsersUserDocumentspython, inifile:
collected 3 items
test_thing.py . [100%]
============================= 2 tests deselected ==============================
=================== 1 passed, 2 deselected in 0.02 seconds ====================
Debido a la búsqueda de coincidencias, es posible que desee hacer algo como poner todas sus pruebas unitarias en un directorio llamado unittest
y luego marcar los lentos como slow_unittest
(para que coincida accidentalmente con una prueba que, por casualidad, tiene lento en el nombre). Entonces podrías usar -k 'unittest and not slow_unittest'
para que coincida con todas sus pruebas unitarias rápidas.
Más ejemplos de uso de marcadores de Pytest