¿Cómo puedo repetir cada prueba varias veces en una ejecución de py.test?

6 minutos de lectura

Avatar de usuario de Martin Del Vecchio
Martín Del Vecchio

Quiero ejecutar cada elemento py.test seleccionado un número arbitrario de veces, secuencialmente.
No veo ningún mecanismo py.test estándar para hacer esto.

Intenté hacer esto en el pytest_collection_modifyitems() gancho. Modifiqué la lista de elementos pasados ​​para especificar cada elemento más de una vez. La primera ejecución de un elemento de prueba funciona como se esperaba, pero eso parece causar algunos problemas en mi código.

Además, preferiría tener un objeto de elemento de prueba único para cada ejecución, ya que uso id (elemento) como clave en varios códigos de informes. Desafortunadamente, no puedo encontrar ningún código py.test para duplicar un elemento de prueba, copy.copy() no funciona, y copy.deepcopy() obtiene una excepción.

¿Alguien puede sugerir una estrategia para ejecutar una prueba varias veces?

Una estrategia posible es parametrizar la prueba en cuestión, pero no usar explícitamente el parámetro.

Por ejemplo:

@pytest.mark.parametrize('execution_number', range(5))
def run_multiple_times(execution_number):
    assert True

La prueba anterior debe ejecutarse cinco veces.

Consulte la documentación de parametrización: https://pytest.org/latest/parametrize.html

  • Esto ejecutará la prueba el número de veces especificado en el archivo de prueba. No logra mi objetivo de ejecutar una prueba un número arbitrario de veces, según lo especificado por una opción de línea de comandos.

    – Martín Del Vecchio

    22 de febrero de 2014 a las 2:37

  • Mis disculpas, entendí completamente mal su pregunta. Creo que descubrí cómo hacer lo que quieres, que agregaré como otra respuesta (ya que esta es completamente incorrecta :).

    – Frank T.

    23 de febrero de 2014 a las 2:14

  • Me alegro de que esta respuesta esté aquí. Creo que se suma al contexto para futuros usuarios que buscan posibles soluciones.

    – morecm

    1 de diciembre de 2015 a las 14:36

  • Buena solución si desea “codificar” la cantidad de veces que se debe ejecutar la prueba

    – Antonio

    15 de febrero de 2018 a las 12:56

  • Esto es particularmente útil para depurar la prueba “flakey” ocasional que falla 1 de cada 25 veces debido a los efectos secundarios de los datos del dispositivo, etc.

    – agitador

    02/09/2020 a las 23:30

El módulo PyTest pytest-repetir existe para este propósito, y recomiendo usar módulos donde sea posible, en lugar de volver a implementar su funcionalidad usted mismo.

Para usarlo simplemente agregue pytest-repeat para usted requirements.txt o pip install pytest-repeatluego ejecute sus pruebas con --count n.

Avatar de usuario de Frank T
franco t

Para ejecutar cada prueba varias veces, parametrizaremos mediante programación cada prueba a medida que se generan las pruebas.

Primero, agreguemos la opción de analizador (incluya lo siguiente en uno de sus conftest.py):

def pytest_addoption(parser):
    parser.addoption('--repeat', action='store',
        help='Number of times to repeat each test')

Ahora agregamos un gancho “pytest_generate_tests”. Aquí es donde ocurre la magia.

def pytest_generate_tests(metafunc):
    if metafunc.config.option.repeat is not None:
        count = int(metafunc.config.option.repeat)

        # We're going to duplicate these tests by parametrizing them,
        # which requires that each test has a fixture to accept the parameter.
        # We can add a new fixture like so:
        metafunc.fixturenames.append('tmp_ct')

        # Now we parametrize. This is what happens when we do e.g.,
        # @pytest.mark.parametrize('tmp_ct', range(count))
        # def test_foo(): pass
        metafunc.parametrize('tmp_ct', range(count))

Corriendo sin la bandera de repetición:

(env) $ py.test test.py -vv
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 2 items 

test.py:4: test_1 PASSED
test.py:8: test_2 PASSED

=========================== 2 passed in 0.01 seconds ===========================

Corriendo con la bandera de repetición:

(env) $ py.test test.py -vv --repeat 3
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 6 items 

test.py:4: test_1[0] PASSED
test.py:4: test_1[1] PASSED
test.py:4: test_1[2] PASSED
test.py:8: test_2[0] PASSED
test.py:8: test_2[1] PASSED
test.py:8: test_2[2] PASSED

=========================== 6 passed in 0.01 seconds ===========================

Otras lecturas:

  • Si bien este método puede funcionar, usé su sugerencia para encontrar una forma más simple, que no requiera argumentos parametrizados, etc. Lo publicaré y lo aceptaré como la respuesta. Gracias por tu sugerencia; me llevó directamente a mi solución.

    – Martín Del Vecchio

    26/02/2014 a las 20:36

  • Trabajando en un nuevo proyecto, vine aquí para averiguar cómo lo había hecho anteriormente. Ahora entiendo que esta solución no requiere que declare un parámetro de dispositivo para cada prueba. Así que estoy seleccionando esta respuesta como correcta y estoy usando su estrategia en mi nuevo proyecto. ¡Gracias!

    – Martín Del Vecchio

    20 de julio de 2017 a las 18:48

  • ¿Cómo se repite todo el archivo de prueba en orden? Aquí la prueba 1 se ejecuta 3 veces, ¿qué hay de ejecutar 1,2,3 (en orden) 3 veces?

    – mungayree

    30 de abril de 2020 a las 23:09

Avatar de usuario de Martin Del Vecchio
Martín Del Vecchio

Basado en la sugerencia de Frank T, encontré una solución muy simple en el pytest_generate_tests() gritar:

parser.addoption ('--count', default=1, type="int", metavar="count", help='Run each test the specified number of times')

def pytest_generate_tests (metafunc):
    for i in range (metafunc.config.option.count):
        metafunc.addcall()

Ahora ejecutando py.test --count 5 hace que cada prueba se ejecute cinco veces en la sesión de prueba.

Y no requiere cambios en ninguna de nuestras pruebas existentes.

Tiempo pytest-repeat (la respuesta más popular) no funciona para unittest pruebas de clase, pytest-flakefinder lo hace:

pip install pytest-flakefinder
pytest --flake-finder --flake-runs=5 tests...

Antes de encontrar test-flakefinder, Escribí un pequeño truco de un script que hace algo similar. Puedes encontrarlo aquí. La parte superior del script incluye instrucciones sobre cómo se puede ejecutar.

  • gracias por mencionar pytest-repeat

    – Edmundo

    10 de febrero a las 13:48

avatar de usuario de user7610
usuario7610

Basado en lo que he visto aquí, y dado que ya hago algunos filtros de pruebas en pytest_collection_modifyitems, mi método de elección es el siguiente. En conftest.py

def pytest_addoption(parser):
    parser.addoption ('--count', default=1, type="int", metavar="count", help='Run each test the specified number of times')


def pytest_collection_modifyitems(session, config, items):
    count = config.option.count
    items[:] = items * count  # add each test multiple times

  • gracias por mencionar pytest-repeat

    – Edmundo

    10 de febrero a las 13:48

Avatar de usuario de Artyom Vasilyev
Artem Vasiliev

He estado buscando una solución simple durante mucho tiempo. Solo tuve que ejecutar una prueba n-número de veces. No debería haberse caído ni una vez. Resolví este problema de la manera más simple y estúpida posible, pero funcionó para mí.

def run_multiple_times(number):
    i = 0
    while i < number:
        #test
        i += 1
run_multiple_times(5)

¿Ha sido útil esta solución?