Skip to content

Entendendo e Usando Fixtures no pytest

📌 O que são Fixtures e por que usá-las?

Quando escrevemos testes, frequentemente precisamos preparar um ambiente de teste antes de rodá-los. Isso pode envolver a criação de objetos, a configuração de variáveis ou a inicialização de serviços.

Podemos fazer isso dentro de cada teste, mas isso gera código repetitivo. Para evitar essa repetição e tornar os testes mais organizados, usamos Fixtures no pytest.

🔹 O que é uma Fixture?

No pytest, uma Fixture é uma função especial que:
- Configura um ambiente de teste antes do teste rodar.
- Fornece dados ou objetos necessários para o teste.
- Pode incluir código de limpeza (teardown) para rodar após o teste.

Vantagens das Fixtures:

✅ Evita repetição de código entre testes.
✅ Facilita a manutenção, pois todas as configurações ficam centralizadas.
✅ Torna os testes mais organizados e modulares.
✅ Pode ser configurada para rodar automaticamente em vários testes.

📌 Exemplo Prático: Testando um Sistema de Pedidos

Cenário:

Temos um sistema que gerencia pedidos de um restaurante. Cada pedido tem um nome do cliente, uma lista de itens e um status ("pendente", "em preparo" ou "entregue").

Queremos testar a funcionalidade de:
1. Criar pedidos.
2. Alterar o status do pedido.

Se não usarmos Fixtures, teríamos que criar objetos de pedido manualmente em cada teste. Isso tornaria o código repetitivo.

Com Fixtures, podemos criar automaticamente um pedido de teste antes de cada teste rodar.

🔹 Passo 1: Criando a Fixture

Aqui, criamos uma Fixture chamada pedido_teste que retorna um pedido pronto para ser usado nos testes.

No arquivo pedidos.py, temos a classe Pedido que representa um pedido do restaurante:

class Pedido:
    def __init__(self, cliente, itens):
        self.cliente = cliente
        self.itens = itens
        self.status = "pendente"

    def atualizar_status(self, novo_status):
        self.status = novo_status

Agora, vamos criar a Fixture no arquivo test_pedidos.py:

import pytest

@pytest.fixture
def pedido_teste():
    """Cria um pedido de teste antes de cada teste rodar."""
    return Pedido(cliente="João", itens=["Pizza", "Suco"])

O que acontece aqui?

🔹 Criamos a classe Pedido, que contém um cliente, itens e um status inicial como "pendente".
🔹 Criamos uma Fixture chamada pedido_teste, que retorna um pedido pronto para ser usado nos testes.
🔹 Como essa Fixture será chamada antes de cada teste, evitamos repetição de código nos testes.

🔹 Passo 2: Usando a Fixture nos Testes

Agora podemos usar pedido_teste simplesmente passando-a como argumento nas funções de teste.

def test_criacao_pedido(pedido_teste):
    """Testa se um pedido é criado corretamente."""
    assert pedido_teste.cliente == "João"
    assert pedido_teste.itens == ["Pizza", "Suco"]
    assert pedido_teste.status == "pendente"

def test_atualizar_status_pedido(pedido_teste):
    """Testa se conseguimos atualizar o status do pedido."""
    pedido_teste.atualizar_status("em preparo")
    assert pedido_teste.status == "em preparo"

O que acontece aqui?

✅ Em test_criacao_pedido, verificamos se o pedido foi criado corretamente.
✅ Em test_atualizar_status_pedido, testamos se conseguimos mudar o status do pedido corretamente.

Por que usar a Fixture aqui?

Sem a Fixture, precisaríamos criar um novo Pedido em cada teste, assim:

def test_criacao_pedido():
    pedido = Pedido(cliente="João", itens=["Pizza", "Suco"])
    assert pedido.cliente == "João"
    assert pedido.itens == ["Pizza", "Suco"]
    assert pedido.status == "pendente"

def test_atualizar_status_pedido():
    pedido = Pedido(cliente="João", itens=["Pizza", "Suco"])
    pedido.atualizar_status("em preparo")
    assert pedido.status == "em preparo"

Isso repetiria o código de criação do pedido em cada teste.

Com a Fixture, garantimos que o objeto de teste sempre existe e está pronto antes dos testes rodarem.

📌 Passo 3: Melhorando a Fixture com múltiplos pedidos

Se quisermos testar diferentes pedidos, podemos modificar a Fixture para receber parâmetros e criar pedidos com diferentes clientes e itens.

@pytest.fixture
def pedido_teste(request):
    """Cria um pedido com diferentes valores, dependendo do teste."""
    cliente, itens = request.param
    return Pedido(cliente=cliente, itens=itens)

Agora, podemos criar múltiplos pedidos sem duplicar código:

import pytest

@pytest.mark.parametrize("pedido_teste", [
    ("João", ["Pizza", "Suco"]),
    ("Maria", ["Hambúrguer", "Refrigerante"]),
    ("Carlos", ["Salada", "Água"])
], indirect=True)
def test_atualizar_status_pedido(pedido_teste):
    pedido.atualizar_status("em preparo")
    assert pedido.status == "em preparo"

Agora testamos vários pedidos diferentes sem precisar criar cada um manualmente! O argumento indirect=True indica que os dados devem ser passados para a Fixture, e não para a função de teste diretamente.

🔹 Resumo

O que as Fixtures fazem? Vantagens
Criam objetos de teste automaticamente antes de cada teste Evita código repetitivo
Permitem configurar e limpar recursos Facilita a manutenção
Melhoram a organização dos testes Código mais limpo e reutilizável

Quando usar Fixtures?

  • Quando um mesmo objeto ou configuração é necessária para vários testes.
  • Quando precisamos configurar um ambiente antes de testar.
  • Quando queremos manter os testes organizados e fáceis de modificar.

Aqui complicou um pouco, mas não se preocupe! Se precisar, levante, tome uma água e releia o que não ficou claro. Depois de relaxar um pouco, vamos falar um pouco sobre o próximo conteúdo.