Introdução ao Pytest
Quando começamos a desenvolver projetos em Python, é comum focarmos apenas em “fazer funcionar”. Mas, em projetos profissionais, é essencial garantir que o código funcione de forma confiável mesmo após mudanças. É aí que entram os testes automatizados — e, no universo Python, uma das ferramentas mais populares é o pytest.
O pytest é um framework de testes para Python que permite criar e executar testes de maneira simples, legível e eficiente. Diferente de frameworks mais antigos como o unittest, o pytest oferece uma sintaxe muito mais intuitiva, além de recursos avançados.
Características principais do pytest:
- Simplicidade: você escreve funções normais em Python começando com test_.
- Automatização: o próprio pytest descobre e executa os testes automaticamente.
- Mensagens claras: ao falhar, mostra exatamente qual foi o erro.
- Fixtures: permite criar dados ou objetos reutilizáveis entre testes.
- Plugins: possui muitos plugins (ex.: para integração com bancos de dados, cobertura de testes, etc).
- Compatibilidade: funciona com unittest e nose, frameworks mais antigos.
Tipos de teste
- 1. Testes Unitários:
- Verificam funções ou métodos isolados.
- 2. Testes de Integração:
- Verificam como módulos diferentes interagem.
- 3. Testes Funcionais:
- Verificam se o fluxo completo do sistema atende ao esperado.
Exemplo de teste unitário:
1. A classe Divisão contém um método executar, que recebe como argumentos dois números do tipo ponto flutuante, e que também contém um condicional composto que testa: primeiro, se os argumetos são do tipo inteiro ou de ponto flutuante; e, segundo, se o segundo argumento é igual a zero. Caso os argumentos passem pelo teste, o cálculo é realizado.
Projeto completo: https://github.com/jcarlossc/calculadora-python-pytest
from calculadora.Operacao import Operacao
class Divisao(Operacao):
"""
Classe que implementa a operação de divisão.
"""
def executar(self, num1: float, num2: float) -> float:
if not isinstance(num1, (int, float)) or not isinstance(num2, (int, float)):
raise ValueError("Parâmetros inválidos para divisão.")
elif num2 == 0:
raise ValueError("Divisão por zero não permitida.")
return num1 / num2
2. O teste contém três testes unitários:
2.1. O primeiro testa o cálculo da divisão, ou seja, declara-se o método de teste, instancia-se o objeto Divisão e, por fim, testa-se o método executar.
2.2. No segundo, assim como o primeiro, declara-se o método de teste, instancia-se o objeto Divisão, declara-se o with(Gerenciador de Contexto) para esperar que uma exceção aconteça durante o código(entrada diferente de inteiro ou de ponto flutuante), e, finalmente, testa-se o método executar.
2.3. Por fim, o terceiro teste, que faz o mesmo que o segundo, só que agora, ele lança uma excessão caso o segundo argumento seja igual a zero.
import pytest
from calculadora.Divisao import Divisao
def test_divide():
operacao = Divisao()
assert operacao.executar(8, 2) == 4
def test_divide_não_numeral():
operacao = Divisao()
with pytest.raises(ValueError, match="Parâmetros inválidos para divisão."):
operacao.executar(10, "3")
def test_divisao_por_zero():
operacao = Divisao()
with pytest.raises(ValueError, match="Divisão por zero não permitida."):
operacao.executar(10, 0)
Teste de integração
O teste de integração é uma abordagem de teste de software que visa verificar como módulos, componentes ou serviços de uma aplicação funcionam juntos, garantindo que as interfaces entre eles e a comunicação entre as partes estejam corretas.
Teste de integração entre as classes Divisão e Calculadora.
Projeto completo: https://github.com/jcarlossc/calculadora-python-pytest
from calculadora.Divisao import Divisao
from calculadora.Calculadora import Calculadora
def test_calculadora_divide():
calcular = Calculadora(Divisao())
assert calcular.calcular(9, 3) == 3
Teste funcional
Teste funcional é uma prática de engenharia de software que verifica se um sistema ou aplicativo funciona de acordo com os requisitos e especificações esperados, focando na validação de suas funções, entradas e saídas.
1. O parametrize é um decorator do pytest que gera múltiplas instâncias do mesmo teste com entradas diferentes.
2. O primeiro argumento é uma string com os nomes dos parâmetros separados por vírgula: "operacao,num1,num2,esperado". Esses nomes devem corresponder aos argumentos da função de teste.
3. O segundo argumento é uma lista de tuplas — cada tupla corresponde a um conjunto de valores que serão passados para os parâmetros na ordem definida.
4. No exemplo, o pytest vai criar 1 teste distinto: cada linha da lista produz um caso de teste separado no relatório do pytest.
import pytest
from calculadora.Divisao import Divisao
from calculadora.Calculadora import Calculadora
@pytest.mark.parametrize("operacao,num1,num2,esperado", [
(Divisao(), 20, 4, 5)
])
def test_fluxo_funcional(operacao,num1,num2,esperado):
calcular = Calculadora(operacao)
assert calcular.calcular(num1,num2) == esperado
Conclusão
O pytest é uma ferramenta indispensável para quem deseja levar a qualidade do código Python a sério. Com sua sintaxe simples e recursos poderosos, é possível escrever testes claros e eficientes sem complicação. Se você ainda não utiliza testes automatizados em seus projetos, começar com o pytest pode ser o primeiro passo para transformar a forma como você programa. Muito obrigado e até a próxima
Repositório do projeto: https://github.com/jcarlossc/calculadora-python-pytest
Comentários
Postar um comentário