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

Postagens mais visitadas deste blog