É possível alterar o comportamento da declaração de afirmação do PyTest em Python




testing assert (3)

Se você estiver usando o PyCharm, poderá adicionar um ponto de interrupção de exceção para interromper a execução sempre que uma declaração falhar. Selecione Exibir pontos de interrupção (CTRL-SHIFT-F8) e adicione um manipulador de exceção em aumento para AssertionError. Observe que isso pode retardar a execução dos testes.

Caso contrário, se você não se importar em fazer uma pausa no final de cada teste com falha (pouco antes de ele errar), e não no ponto em que a afirmação falhar, você terá algumas opções. Observe, porém, que, nesse ponto, vários códigos de limpeza, como o fechamento de arquivos que foram abertos no teste, já podem ter sido executados. As opções possíveis são:

  1. Você pode dizer ao pytest para colocá-lo no depurador por erros, usando a opção --pdb .

  2. Você pode definir o decorador a seguir e decorar cada função de teste relevante com ele. (Além de registrar uma mensagem, você também pode iniciar um pdb.post_mortem nesse ponto ou até mesmo um code.interact interativo. code.interact com os locais do quadro em que a exceção se originou, conforme descrito nesta resposta .)

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. Se você não desejar decorar manualmente todas as funções de teste, poderá definir um dispositivo autouse que inspeciona 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)

Estou usando instruções de declaração Python para corresponder ao comportamento real e esperado. Eu não tenho controle sobre isso como se houvesse um caso de erro de abortamento. Desejo assumir o controle do erro de asserção e quero definir se quero interromper o testcase ao declarar falha ou não.

Também quero adicionar algo como, se houver um erro de asserção, o caso de teste deve ser pausado e o usuário pode retomar a qualquer momento.

Eu não tenho nenhuma idéia de como fazer isso

Exemplo de código, estamos usando pytest aqui

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

Below is my expectation

Quando assert lança um assertionError, devo ter a opção de pausar o testcase e posso depurar e continuar mais tarde. Para pausar e continuar, tkinter módulo tkinter . Vou fazer uma função de afirmação como abaixo

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)

No futuro, tenho que alterar todas as declarações assert com esta função como

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

Isso é muito esforço para mim, pois tenho que fazer mudanças em milhares de lugares onde costumava afirmar. Existe alguma maneira fácil de fazer isso no pytest

Summary: preciso de algo em que possa pausar o testcase em caso de falha e depois retomar após a depuração. Eu conheço o tkinter e é por isso que o usei. Quaisquer outras idéias serão bem-vindas

Note : O código acima ainda não foi testado. Também pode haver pequenos erros de sintaxe

Edit: Obrigado pelas respostas. Estendendo esta questão um pouco à frente agora. E se eu quiser mudar o comportamento de afirmar. Atualmente, quando há um erro de asserção, o testcase sai. E se eu quiser escolher se preciso da saída do testcase em uma determinada declaração de falha ou não. Eu não quero escrever a função de afirmação personalizada, como mencionado acima, porque dessa forma eu tenho que mudar em vários locais


Uma solução simples, se você estiver disposto a usar o Visual Studio Code, poderá ser usar pontos de interrupção condicionais .

Isso permitiria configurar suas asserções, por exemplo:

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

Em seguida, adicione um ponto de interrupção condicional na sua linha de afirmação que só será interrompida quando sua afirmação falhar:


Você pode conseguir exatamente o que deseja, sem absolutamente nenhuma modificação de código com pytest --pdb .

Com o seu exemplo:

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

Execute com --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)

Assim que um teste falha, você pode depurá-lo com o depurador python embutido. Se você tiver concluído a depuração, poderá continue com o restante dos testes.





assert