Estoy usando declaraciones de afirmación de Python para que coincida con el comportamiento real y esperado. No tengo control sobre estos, ya que si hay una prueba de error, aborta los casos. Quiero tomar el control del error de aserción y quiero definir si quiero abortar el caso de prueba en caso de fallo o no.

También quiero agregar algo como si hay un error de aserción, entonces el caso de prueba debe pausarse y el usuario puede reanudar en cualquier momento.

No tengo idea de cómo hacer esto

Ejemplo de código, estamos usando pytest aquí

import pytest
def test_abc():
    a = 10
    assert a == 10, "some error message"

Below is my expectation

Cuando afirmar arroja un aserción de error, debería tener la opción de pausar el caso de prueba y puedo depurar y luego reanudar. Para pausar y reanudar, usaré el módulo tkinter. Haré una función de aserción como a continuación

import tkinter
import tkinter.messagebox

top = tkinter.Tk()

def _assertCustom(assert_statement, pause_on_fail = 0):
    #assert_statement will be something like: assert a == 10, "Some error"
    #pause_on_fail will be derived from global file where I can change it on runtime
    if pause_on_fail == 1:
        try:
            eval(assert_statement)
        except AssertionError as e:
            tkinter.messagebox.showinfo(e)
            eval (assert_statement)
            #Above is to raise the assertion error again to fail the testcase
    else:
        eval (assert_statement)

En el futuro, tengo que cambiar cada declaración de aserción con esta función como

import pytest
def test_abc():
    a = 10
    # Suppose some code and below is the assert statement 
    _assertCustom("assert a == 10, 'error message'")

Este es un esfuerzo demasiado grande para mí, ya que tengo que hacer cambios en miles de lugares donde he usado la afirmación. ¿Hay alguna manera fácil de hacerlo en pytest

Summary: Necesito algo donde pueda pausar el caso de prueba en caso de falla y luego reanudarlo después de la depuración. Sé acerca de tkinter y esa es la razón por la que lo he usado. Cualquier otra idea será bienvenida

Note: el código anterior aún no se ha probado. También puede haber pequeños errores de sintaxis

Editar: Gracias por las respuestas. Extendiendo esta pregunta un poco más adelante ahora. ¿Qué pasa si quiero cambiar el comportamiento de afirmar? Actualmente, cuando hay un error de aserción, sale el caso de prueba. ¿Qué pasa si quiero elegir si necesito salir de caso de prueba en caso de fallo de afirmación particular o no? No quiero escribir una función de aserción personalizada como se mencionó anteriormente porque de esta manera tengo que cambiar en varios lugares

18
Nitesh 10 oct. 2019 a las 14:35

3 respuestas

Si está utilizando PyCharm, puede agregar un punto de interrupción de excepción para pausar la ejecución cada vez que falla una aserción. Seleccione Ver puntos de interrupción (CTRL-SHIFT-F8) y agregue un controlador de excepción en aumento para AssertionError. Tenga en cuenta que esto puede ralentizar la ejecución de las pruebas.

De lo contrario, si no le importa detenerse al final de cada prueba fallida (justo antes de que se produzca un error) en lugar de en el momento en que la afirmación falla, entonces tiene algunas opciones. Sin embargo, tenga en cuenta que en este punto ya podrían haberse ejecutado varios códigos de limpieza, como el cierre de archivos que se abrieron en la prueba. Las opciones posibles son:

  1. Puede decirle a pytest que lo coloque en el depurador de errores utilizando - opción pdb.

  2. Puede definir el siguiente decorador y decorar cada función de prueba relevante con él. (Además de registrar un mensaje, también puede iniciar un pdb.post_mortem en este punto, o incluso un code.interact interactivo con los locales del marco donde se originó la excepción, como se describe en esta respuesta.)

from functools import wraps

def pause_on_assert(test_func):
    @wraps(test_func)
    def test_wrapper(*args, **kwargs):
        try:
            test_func(*args, **kwargs)
        except AssertionError as e:
            tkinter.messagebox.showinfo(e)
            # re-raise exception to make the test fail
            raise
    return test_wrapper

@pause_on_assert
def test_abc()
    a = 10
    assert a == 2, "some error message"

  1. Si no desea decorar manualmente cada función de prueba, puede definir un dispositivo de uso automático que inspeccione sys.last_value:
import sys

@pytest.fixture(scope="function", autouse=True)
def pause_on_assert():
    yield
    if hasattr(sys, 'last_value') and isinstance(sys.last_value, AssertionError):
        tkinter.messagebox.showinfo(sys.last_value)
4
Uri Granta 16 oct. 2019 a las 09:46

Puede lograr exactamente lo que desea sin absolutamente ninguna modificación de código con pytest --pdb.

Con tu ejemplo:

import pytest
def test_abc():
    a = 9
    assert a == 10, "some error message"

Ejecutar con --pdb:

py.test --pdb
collected 1 item

test_abc.py F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    def test_abc():
        a = 9
>       assert a == 10, "some error message"
E       AssertionError: some error message
E       assert 9 == 10

test_abc.py:4: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /private/tmp/a/test_abc.py(4)test_abc()
-> assert a == 10, "some error message"
(Pdb) p a
9
(Pdb)

Tan pronto como una prueba falla, puede depurarla con el depurador de python incorporado. Si ha terminado de depurar, puede continue con el resto de las pruebas.

7
gnvk 16 oct. 2019 a las 07:55

Una solución simple, si está dispuesto a usar Visual Studio Code, podría ser usar puntos de corte condicionales.

Esto le permitiría configurar sus afirmaciones, por ejemplo:

import pytest
def test_abc():
    a = 10
    assert a == 10, "some error message"

Luego agregue un punto de interrupción condicional en su línea de afirmación que solo se romperá cuando su afirmación falle:

enter image description here

4
Nick Martin 22 oct. 2019 a las 10:13
58321991