Pytest: Framework de Testes Funcional e Flexível
Pytest é uma ferramenta de teste amplamente utilizada em projetos Python, conhecida por sua simplicidade e extensibilidade. Ela permite a criação de testes unitários, funcionais e de integração de maneira eficiente.
Instalação
Para instalar o Pytest, utilize o gerenciador de pacotes pip:
pip install pytest
Escrevendo Testes
No Pytest, os testes podem ser definidos em funções ou classes. Por convenção, nomes de arquivos devem iniciar com test_, funções de teste com test_ e classes de teste com Test. Exemplo em um arquivo test_exemplo.py:
def test_soma_elementar():
assert 3 + 4 == 7
class TestExemploClasse:
def test_verificacao_basica(self):
assert True
Uso de Assertivas
Pytest utiliza a instrução assert do Python para validações. Mensagens de erro personalizadas podem ser adicionadas para facilitar a depuração:
def test_operacoes_com_mensagem():
valor = 10 * 2
assert valor == 20, f"Esperado 20, mas obtido {valor}"
assert "python" in ["java", "python", "c#"], "Lista deve conter 'python'"
Testando Exceções
Para verificar se uma exceção específica é lançada, utilize pytest.raises:
import pytest
def test_excecao_esperada():
with pytest.raises(ValueError):
int("texto_invalido")
Marcadores (Markers)
Marcadores personalizados permitem categorizar testes. Eles são aplicados com @pytest.mark.nome e, em modo estrito, devem ser registrados no arquivo pytest.ini. Para executar testes filtrados:
pytest -m "conexao and prioridade_alta"
Pulando e Esperando Falhas
Pytest oferece decorators para pular testes ou marcá-los como esperadamente falhos:
@pytest.skip(reason): Pula o teste incondicionalmente.@pytest.skipif(condition, reason): Pula com base em uma condição.@pytest.xfail(reason): Indica que o teste é esperado falhar.
Dentro do teste, funções como pytest.skip() podem ser chamadas para alterar o fluxo:
def test_cenario_condicional():
if condicao_complexa():
pytest.skip("Ignorando em ambientes específicos")
Executando Testes
O comando pytest suporta divesras opções de controle:
-q: Modo silencioso, reduzindo a saída.-v: Modo verboso, mostrando detalhes de cada teste.-s: Exibe saídas deprint()durante a execução.- Executar todos os testes em um diretório:
pytest diretorio/ - Executar um módulo específico:
pytest test_modulo.py - Filtrar testes por nome:
pytest -k "teste_a or teste_b" - Parar após a primeira falha:
pytest -x - Repetir testes falhos:
pytest --lf - Listar testes sem executar:
pytest --collect-only
Configuração e Limpeza de Testes
O Pytest fornece métodos para preparação e limpeza em diferentes níveis:
- Nível de módulo:
setup_module()eteardown_module() - Nível de classe:
setup_class()eteardown_class() - Nível de método:
setup_method()eteardown_method()
Exemplo:
def setup_module():
print("Iniciando configuração do módulo")
def teardown_module():
print("Limpando recursos do módulo")
class TestComSetup:
def setup_method(self):
self.recurso = "valor_temporario"
def test_uso_recurso(self):
assert self.recurso == "valor_temporario"
Fixtures Personalizadas
Fixtures encapsulam lógicas de setup e teardown, usando yield para separar as fases. Elas podem ser definidas em conftest.py para compartilhamento.
import pytest
@pytest.fixture(scope="function")
def dados_conexao():
print("Configurando conexão")
conexao = {"host": "localhost", "porta": 8080}
yield conexao
print("Fechando conexão")
def test_conexao_valida(dados_conexao):
assert dados_conexao["porta"] == 8080
Parâmetros de fixtures incluem scope (session, package, module, class, functon) e autouse para aplicação automática.
Parametrização de Testes
Para testes orientados a dados, utilize @pytest.mark.parametrize para fornecer múltiplos cenários:
import pytest
casos_de_teste = [
(1, 1, 2),
(0, 0, 0),
(-1, 2, 1),
(10.5, 20.5, 31.0)
]
@pytest.mark.parametrize("a, b, resultado_esperado", casos_de_teste)
def test_soma_parametrizada(a, b, resultado_esperado):
resultado_atual = a + b
assert resultado_atual == resultado_esperado