O Que Objeto Indireto - O que é um objeto direto e indireto? - Ponto do Conhecimento
O que é um objeto direto e indireto? - Ponto do Conhecimento

Um guia direto sobre fixtures indiretas no pytest

O conceito de o que objeto indireto no pytest se resume a uma funcionalidade específica e muito útil que a maioria dos desenvolvedores não conhece direito. Quando você marca um parâmetro de parametrização como indirect, o pytest passa aquele valor primeiro para uma fixture antes de entregar ao teste. Isso permite transformar, calcular ou validar dados antes que eles cheguem à função de teste.

Entendendo na prática o que objeto indireto significa

Vamos direto ao exemplo. Suponha que você tenha um teste que precisa de um caminho de arquivo, mas esse caminho é construído dinamicamente a partir de um nome de arquivo fornecido na parametrização. Sem indireto, você faria isso manualmente dentro do teste. Com indireto, você delega essa lógica para uma fixture.

Imagine esta situação: você está parametrizando testes com nomes de arquivos como ["relatório.pdf", "dados.json", "config.xml"]. Para cada um desses nomes, você precisa criar um arquivo temporário, escrever conteúdo dentro dele e devolver o path. Fazer isso dentro do corpo do teste é bagunça. Usar uma fixture indireta é mais limpo. Aqui está como fica:

import pytest
import tempfile
import os

@pytest.fixture
def arquivo_temporario(request):
    nome = request.param
    conteudo = f"dados para {nome}"
    with tempfile.NamedTemporaryFile(mode='w', suffix=nome, delete=False) as f:
        f.write(conteudo)
        return f.name
    yield
    os.unlink(temp_name)

@pytest.mark.parametrize("arquivo_temporario", 
    ["relatorio.pdf", "dados.json", "config.xml"], 
    indirect=True)
def teste_processar(arquivo_temporario):
    assert os.path.exists(arquivo_temporario)
    with open(arquivo_temporario) as f:
        assert f.read().startswith("dados para")

O ponto-chave aqui é o argumento indirect=True no decorador parametrize. Sem ele, o pytest tentaria passar a string diretamente como argumento do teste. Com ele, o pytest encaminha o valor para a fixture indicada e usa o retorno dela. Tem um detalhe que pega todo mundo no início. Você pode misturar parâmetros diretos e indiretos no mesmo parametrize. Por exemplo, se seu teste recebe dois argumentos e só um deles precisa passar por transformação:

@pytest.mark.parametrize("arquivo_temporario", 
    ["a.txt", "b.txt"], 
    indirect=True)
@pytest.mark.parametrize("modo", ["r", "rb"])
def teste_leitura(arquivo_temporario, modo):
    with open(arquivo_temporario, modo) as f:
        pass

Neste caso, apenas arquivo_temporario é processado pela fixture. modo é passado diretamente, sem interferência da fixture.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Problemas reais que aparecem no dia a dia

Já vi gente tentarem usar fixtures indiretas com fixtures que têm escopo de módulo ou sessão e ter comportamento inesperado. O problema é que o request.param só é resolvido no momento em que a fixture é chamada. Se a fixture tem escopo amplo e o parâmetro varia entre chamadas, o pytest pode reutilizar o valor cacheado da fixture em vez de recalculá-lo para cada combinação de parametrização. A solução que funciona de forma consistente é manter fixtures indiretas com escopo de função (que é o padrão) ou, se precisar de escopo maior, garantir que a fixture não dependa de valores que variam na parametrização. Uma abordagem alternativa que costuma ser mais previsível é não usar indirect e simplesmente chamar a fixture manualmente dentro do teste, passando request quando necessário.

Outro cenário problemático: quando você tem múltiplas fixtures envolvidas no mesmo parâmetro. O pytest não resolve essa cadeia automaticamente. Cada fixture na cadeia precisa ser marcada como indirect individualmente, ou você recebe erros de argumento inválido. Um caso concreto que encontrei recentemente: estava construindo uma suite de testes de API onde cada teste precisava de um token de autenticação gerado a partir de credenciais parametrizadas. A fixture recebia o usuário e senha via request.param, chamava um endpoint de login e retornava o token. Usei indirect=True no parametrização. O problema apareceu quando adicionei uma segunda fixture que dependia desse token para criar um recurso no sistema. O pytest tentou injetar o token como um parâmetro direto em vez de chamar a fixture correspondente. A correção foi separar em dois levels de parametrização distintos, usando fixtures aninhadas com escopo adequado e garantindo que cada nível tivesse seu indirect configurado corretamente.

Quando não usar indireto

Fixtures indiretas não são bala de prata. Elas adicionam uma camada de complexidade que nem sempre justifica o uso. Se a transformação dos dados é simples — como converter uma string para int ou concatenar dois campos —, faça isso diretamente no teste. O overhead de debugar uma fixture indireta que não está fazendo o esperado vale mais do que a economia de três linhas de código. Performance também é um fator que as pessoas ignoram. Fixtures indiretas adicionam uma chamada de fixture extra por cada combinação de parametrização. Em suites grandes com centenas de combinações, isso pode aumentar o tempo de setup significativamente. Em um projeto onde tinha cerca de 200 combinações parametrizadas usando indirect com fixtures pesadas de setup de banco de dados, a troca para chamadas manuais reduziu o tempo de execução dos testes de configuração de 4 minutos para 30 segundos.

Se a transformação dos seus dados for complexa o suficiente para justificar uma fixture, mas a parametrização não é tão grande assim, considere usar uma abordagem híbrida. Crie uma fixture comum sem indirect e chame-a explicitamente dentro do corpo do teste quando necessário. Isso dá controle total sobre quando a fixture é executada e evita surpresas com o mecanismo de resolução do pytest.

Dica prática para evitar erros comuns

Sempre verifique se o nome da fixture no parametrize corresponde exatamente ao nome da função fixture. Um erro de digitação comum é colocar o nome do parâmetro correto no teste mas errar no nome da fixture no parametrize. O pytest não levanta erro nesses casos — ele simplesmente ignora o indirect e passa o valor bruto, causando falhas difíceis de diagnosticar. Use pytest --setup-show durante o desenvolvimento para visualizar a cadeia exata de chamadas de fixture e confirmação de que o indirect está funcionando como esperado. Isso economiza horas de debug em comparações de "por que meu valor não está sendo transformado".

Resumo

Objeto indireto no pytest é a técnica de passar valores parametrizados através de uma fixture antes de chegarem ao teste. É útil quando a transformação dos dados é não-trivial e se repete em múltiplos testes. É problemático quando misturado com fixtures de escopo amplo ou cadeias de dependência complexas. A regra geral é usar quando o benefício da reutilização de lógica supera o custo adicional de complexidade e debugging.