Trilha de aprendizado · Nível 8 · Tutorial 5

Verificar integração com arquivos temporários

Testar a colaboração entre componentes de processamento e persistência usando arquivos reais em diretórios temporários controlados pelo pytest.

  • Nível: Intermediário
  • Duração: 18 min
  • 7 passos
Verificar integração com arquivos temporários

O que você vai percorrer

  1. Definir o fluxo real a verificar Delimite um fluxo de integração local e identifique quais resultados observáveis comprovam seu funcionamento. 2 min
  2. Receber um diretório com tmp_path Solicite ao pytest um diretório temporário exclusivo e construa caminhos de entrada e saída dentro dele. 3 min
  3. Preparar uma entrada conhecida Crie um JSON sintético dentro de tmp_path, chame o leitor real e compare os dados carregados com uma expectativa definida diretamente no teste. 3 min
  4. Verificar o resultado persistido de forma independente Teste o fluxo completo de leitura, soma e gravação, conferindo o JSON persistido sem reutilizar a própria implementação para produzir a expectativa. 3 min
  5. Provocar falhas reproduzíveis Crie cenários controlados de arquivo ausente e JSON malformado, verificando as exceções propagadas e a ausência do arquivo de saída. 3 min
  6. Manter os testes independentes Reconheça como diretórios exclusivos, caminhos explícitos e dados sintéticos evitam dependências entre testes, mesmo quando o pytest mantém resíduos temporários no disco. 2 min
  7. Consolidar e executar a suíte de integração Reúna o fluxo e os testes em arquivos locais, execute os três cenários e confirme que a suíte permanece isolada e repetível. 4 min

O que você vai aprender

  • Receber a fixture pronta tmp_path pelo parâmetro de uma função de teste.
  • Preparar arquivos temporários conhecidos para verificar leitura, processamento e gravação.
  • Verificar resultados persistidos e falhas determinísticas, como arquivo ausente ou JSON inválido.
  • Manter os testes independentes dos arquivos pessoais e dos caminhos específicos da máquina.

Antes de começar

  • Isolar dependências com substitutos de teste
  • Manipular caminhos com pathlib
  • Ler e gravar arquivos de texto com with
  • Salvar e carregar dados em JSON

Passo 1 de 7

Definir o fluxo real a verificar

Delimite um fluxo de integração local e identifique quais resultados observáveis comprovam seu funcionamento.

Da unidade isolada à colaboração real

O que será integrado?

No tutorial anterior, os substitutos permitiram verificar componentes isoladamente. Agora, o foco muda: vamos exercitar a colaboração entre componentes reais e o sistema de arquivos local.

O caso condutor recebe dois caminhos explicitamente — entrada e saída — e executa este fluxo:

  1. lê uma lista JSON de quantidades inteiras;
  2. calcula a soma dessas quantidades;
  3. grava um resumo JSON com o campo total.

O escopo continua controlado: não há banco de dados, rede ou outro serviço externo.

Percurso dos dados

Diagrama do fluxo entre um arquivo JSON de entrada, um leitor, o cálculo da soma, um gravador e um arquivo JSON de saída.

A integração atravessa componentes locais reais e termina em um efeito observável no arquivo de saída.

O que comprova o sucesso

Observe o efeito persistido

Um retorno correto não basta para comprovar todo o fluxo. A operação também precisa produzir o arquivo de saída no caminho recebido, com o conteúdo previsto pelo contrato.

Por isso, o resultado principal da integração é o conteúdo persistido. A verificação deve alcançar o último ponto observável do percurso, em vez de parar no valor calculado em memória.

Exemplo

Contrato do caso condutor

Entrada JSON: [4, 7, 2]

Saída esperada, interpretada como JSON: {"total": 13}

Se a operação retornar 13, mas não gravar esse resumo no caminho de saída, a colaboração está incompleta. Espaços ou indentação diferentes não mudam o significado do JSON.

Relacione etapa e evidência

O que cada observação demonstra?

Associe cada observação ao que ela permite concluir sobre o fluxo.

Toque em um item e depois no par correspondente.

Passo 2 de 7

Receber um diretório com tmp_path

Solicite ao pytest um diretório temporário exclusivo e construa caminhos de entrada e saída dentro dele.

O pytest fornece o diretório

Uma fixture pronta

Para receber um diretório temporário, inclua tmp_path como parâmetro da função de teste. Ao executar o teste, o pytest reconhece esse nome e fornece um objeto pathlib.Path que aponta para um diretório temporário exclusivo daquele teste.

Você não cria tmp_path nem importa uma variável com esse nome. O recurso é solicitado pela assinatura da função.

Diagrama em que o pytest fornece um diretório temporário exclusivo a uma função de teste, da qual partem caminhos para dois arquivos.

O pytest cria o diretório e entrega seu caminho ao teste; os caminhos dos arquivos são construídos dentro dele.

Construir caminhos dentro do diretório

Diretório existente, arquivos ainda ausentes

O diretório indicado por tmp_path já existe quando o teste começa. Use o operador / de Path para construir caminhos filhos, sem depender de caminhos absolutos ou específicos da sua máquina.

Construir entrada e saida não cria esses arquivos. Eles somente passarão a existir quando alguma operação gravar conteúdo neles.

Teste demonstrativo completo

Salve como tests/test_caminhos.py e execute com python -m pytest tests/test_caminhos.py.

python
def test_constroi_caminhos_no_diretorio_temporario(tmp_path):
    entrada = tmp_path / "quantidades.json"
    saida = tmp_path / "resumo.json"

    assert tmp_path.is_dir()
    assert entrada.parent == tmp_path
    assert saida.parent == tmp_path
    assert not entrada.exists()
    assert not saida.exists()

Dica

Deixe o pytest fazer a chamada

Não chame essa função de teste manualmente. Execute-a com o pytest para que o parâmetro tmp_path seja preenchido.

Confira a solicitação e o caminho

Complete a assinatura

Complete o parâmetro que faz o pytest fornecer o diretório temporário:

def test_processamento(_____):

Depois, o teste poderá construir entrada = tmp_path / "dados.json".

Caminho não é arquivo criado

Após executar entrada = tmp_path / "dados.json", o arquivo dados.json já existe no diretório temporário.

Passo 3 de 7

Preparar uma entrada conhecida

Crie um JSON sintético dentro de tmp_path, chame o leitor real e compare os dados carregados com uma expectativa definida diretamente no teste.

O teste controla a entrada

Prepare antes de chamar

Neste cenário, o próprio teste cria um arquivo JSON conhecido dentro de tmp_path. Em seguida, chama o leitor real e compara o resultado com uma lista esperada.

A entrada deve ser gravada diretamente pelo teste. Se usássemos o gravador da aplicação para preparar o arquivo, um defeito nele poderia interferir na verificação do leitor.

Preparação, ação e verificação

O recurso temporário participa das três etapas: o teste prepara o JSON, o leitor real acessa o arquivo e o valor carregado é comparado com a expectativa.

Diagrama em três etapas mostrando a criação de um JSON em uma pasta temporária, sua leitura por um componente Python e a comparação com uma lista esperada.

O teste cria seus próprios dados antes de chamar o leitor real.

Código real do exemplo

Crie o módulo processamento.py

Na raiz de uma pasta local, crie processamento.py com o código completo abaixo. O módulo reúne leitura, processamento e persistência para os próximos testes. Nesta etapa, o foco é carregar_quantidades, que recebe o caminho explicitamente e lê texto em UTF-8.

processamento.py

python
import json
from pathlib import Path


def carregar_quantidades(caminho: Path) -> list[int]:
    texto = caminho.read_text(encoding="utf-8")
    return json.loads(texto)


def calcular_total(quantidades: list[int]) -> int:
    return sum(quantidades)


def salvar_resumo(caminho: Path, total: int) -> None:
    resumo = {"total": total}
    texto = json.dumps(resumo, ensure_ascii=False)
    caminho.write_text(texto, encoding="utf-8")


def executar_fluxo(entrada: Path, saida: Path) -> None:
    quantidades = carregar_quantidades(entrada)
    total = calcular_total(quantidades)
    salvar_resumo(saida, total)

Teste da leitura real

Crie o arquivo de teste

Crie a pasta tests e, dentro dela, o arquivo test_processamento.py. O caminho entrada.json fica sob o diretório recebido por este teste. O arquivo ainda não existe quando o caminho é composto; write_text o cria com dados sintéticos e previsíveis.

tests/test_processamento.py

python
from processamento import carregar_quantidades


def test_carrega_quantidades_de_arquivo_temporario(tmp_path):
    entrada = tmp_path / "entrada.json"
    entrada.write_text("[4, 7, 2]", encoding="utf-8")

    quantidades = carregar_quantidades(entrada)

    assert quantidades == [4, 7, 2]

Dica

Expectativa independente

Escreva a expectativa diretamente no teste. Aqui, [4, 7, 2] expressa claramente o que deve resultar da leitura do JSON preparado, sem pedir à própria aplicação que produza o valor esperado.

Reconheça a sequência

Ordene as operações

Coloque as operações na ordem adequada para verificar a leitura de uma entrada temporária conhecida.

  1. Comparar o resultado com a lista esperada definida no teste.
  2. Chamar `carregar_quantidades` com o caminho preparado.
  3. Gravar diretamente o texto JSON conhecido usando UTF-8.
  4. Compor o caminho `entrada.json` sob `tmp_path`.

Passo 4 de 7

Verificar o resultado persistido de forma independente

Teste o fluxo completo de leitura, soma e gravação, conferindo o JSON persistido sem reutilizar a própria implementação para produzir a expectativa.

Observe o efeito final

A saída é parte do contrato

No fluxo completo, a operação recebe os caminhos de entrada e saída localizados sob tmp_path, lê as quantidades, calcula a soma e grava o resumo.

A verificação não deve se limitar ao retorno da função nem apenas confirmar que a saída existe. O teste precisa abrir o arquivo realmente gravado, decodificar seu JSON e comparar o conteúdo com uma expectativa definida pelo próprio cenário.

Para evitar que erros compatíveis se escondam, confira a saída com read_text() e json.loads(), da biblioteca padrão, em vez de usar o leitor da aplicação como única forma de testar o gravador.

Implementação e verificação por caminhos distintos

Diagrama em que um arquivo de entrada passa pela leitura, soma e gravação até um arquivo de saída; uma verificação independente compara essa saída com uma expectativa preparada separadamente.

A operação produz a saída; o teste segue um caminho independente para observar e comparar o conteúdo persistido.

Teste o fluxo completo

Adicione o cenário de sucesso

No arquivo de testes usado no step anterior, adicione o teste abaixo. Ajuste apenas o nome do módulo importado caso você tenha usado outro nome para o arquivo da aplicação.

Verificação independente do JSON persistido

python
import json

from processamento import processar_arquivo


def test_processa_e_grava_resumo(tmp_path):
    entrada = tmp_path / "quantidades.json"
    saida = tmp_path / "resumo.json"

    entrada.write_text("[4, 7, 9]", encoding="utf-8")
    esperado = {"total": 20}

    processar_arquivo(entrada, saida)

    obtido = json.loads(saida.read_text(encoding="utf-8"))
    assert obtido == esperado

Dica

O que esse assert verifica

saida.read_text() já exige que o arquivo tenha sido criado. json.loads() exige conteúdo JSON decodificável, e a comparação entre dicionários verifica o significado dos dados. Espaços, indentação e ordem textual das chaves não afetam o teste, pois não fazem parte deste contrato.

Escolha uma verificação confiável

Independência da expectativa

Qual verificação detecta conteúdo incorreto mesmo que o arquivo de saída exista?

Execute e justifique

Faça a verificação local

Execute o teste no seu projeto com python -m pytest. Depois, altere temporariamente esperado para {"total": 21} e execute novamente: o teste deve falhar porque o conteúdo persistido não corresponde à expectativa. Restaure {"total": 20} e confirme que ele volta a passar.

Explique a independência do teste

O que você observou nas execuções? Explique também por que {"total": 20} é uma expectativa independente da implementação.

Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 7

Provocar falhas reproduzíveis

Crie cenários controlados de arquivo ausente e JSON malformado, verificando as exceções propagadas e a ausência do arquivo de saída.

Falhas controladas no fluxo

Falhar de propósito, mas sempre do mesmo modo

Um teste de integração também deve verificar falhas previsíveis. Neste step, a operação processar_arquivo(entrada, saida) continua sendo exercitada com componentes reais, mas recebe duas entradas problemáticas:

  • um caminho cujo arquivo não foi criado;
  • um arquivo existente com JSON sintaticamente inválido.

Nos dois casos, a leitura falha antes que a operação abra o arquivo de saída. Portanto, além da exceção específica, o contrato deste exemplo permite verificar que a saída não foi criada.

Onde cada cenário interrompe o fluxo

Os dois cenários param na etapa de leitura e não chegam à gravação.

Diagrama com dois caminhos de entrada: um arquivo ausente e um documento JSON com sintaxe quebrada. Ambos são interrompidos na leitura antes do processamento e da criação da saída.

Arquivo ausente e JSON malformado falham antes da gravação no fluxo deste exemplo.

Atenção

Esta ausência de saída depende do contrato

A verificação assert not saida.exists() é válida porque a implementação do exemplo lê e processa a entrada antes de abrir a saída. Ela não representa uma garantia geral de recuperação ou de gravação atômica.

Cenário 1: arquivo ausente

Crie apenas o caminho

Com tmp_path, compor um caminho não cria o arquivo. Isso permite provocar FileNotFoundError sem apagar arquivos existentes nem tocar em pastas pessoais.

Teste com entrada inexistente

Adicione este teste ao arquivo de testes que já importa pytest e a operação processar_arquivo:

python
def test_nao_cria_saida_quando_entrada_nao_existe(tmp_path):
    entrada = tmp_path / "quantidades.json"
    saida = tmp_path / "resumo.json"

    # O caminho foi construído, mas o arquivo não foi criado.
    with pytest.raises(FileNotFoundError):
        processar_arquivo(entrada, saida)

    assert not saida.exists()

Dica

Determinismo primeiro

Prefira fabricar uma ausência dentro do diretório temporário. Não dependa de permissões, falta de espaço, caminhos fixos ou arquivos pessoais: essas condições variam entre máquinas.

Cenário 2: JSON malformado

O arquivo existe, mas a sintaxe está incompleta

Agora a entrada deve existir. Grave deliberadamente um texto como [10, 20,, que começa uma lista e termina sem fechá-la. Ao tentar decodificá-lo, json.load ou json.loads gera json.JSONDecodeError, propagado pela operação integrada.

Isso é diferente de um JSON sintaticamente válido com dados inadequados ao domínio. Por exemplo, {"quantidade": "muitas"} pode ser um JSON válido, ainda que não atenda ao contrato da aplicação. Aqui, o foco é exclusivamente a falha de decodificação.

Teste com JSON sintaticamente inválido

Garanta que o arquivo de testes também tenha import json:

python
import json


def test_nao_cria_saida_quando_json_e_invalido(tmp_path):
    entrada = tmp_path / "quantidades.json"
    saida = tmp_path / "resumo.json"
    entrada.write_text("[10, 20,", encoding="utf-8")

    with pytest.raises(json.JSONDecodeError):
        processar_arquivo(entrada, saida)

    assert not saida.exists()

Exemplo

O que cada verificação demonstra

pytest.raises(json.JSONDecodeError) confirma a falha específica de decodificação. Já assert not saida.exists() confirma o efeito observável previsto pelo contrato deste fluxo: a gravação não começou após a entrada inválida.

Associe preparação e resultado

Falhas determinísticas

Associe cada preparação ao resultado esperado.

Toque em um item e depois no par correspondente.

Preveja antes de executar

Se quantidades.json contiver apenas [5,, qual exceção o teste deve esperar e qual deve ser o estado de resumo.json após a chamada?

Escreva pelo menos 40 caracteres (0/40).

Passo 6 de 7

Manter os testes independentes

Reconheça como diretórios exclusivos, caminhos explícitos e dados sintéticos evitam dependências entre testes, mesmo quando o pytest mantém resíduos temporários no disco.

Um espaço exclusivo para cada teste

Mesmo nome, recursos diferentes

Duas funções de teste podem criar entrada.json e saida.json com os mesmos nomes. Como cada uma recebe um diretório exclusivo por tmp_path, os caminhos completos são diferentes.

Cada teste deve preparar seus próprios dados, executar a operação e verificar seu próprio resultado. Assim, a suíte não depende da ordem de execução: nenhum teste precisa consumir um arquivo produzido por outro.

Diretórios separados

Observe que nomes de arquivo iguais não representam o mesmo recurso quando estão dentro de diretórios temporários diferentes.

Dois diretórios temporários visualmente separados, cada um contendo seus próprios arquivos JSON de entrada e saída com nomes repetidos.

Cada teste trabalha em seu próprio diretório, ainda que os nomes internos dos arquivos sejam iguais.

Caminhos explícitos e ciclo de vida

O isolamento continua no código testado

Construa os caminhos sob tmp_path e passe-os explicitamente para a operação testada. O código não deve procurar entradas no diretório de trabalho nem depender de um caminho específico da sua máquina.

O pytest administra a retenção e a limpeza dos diretórios temporários conforme sua política e configuração. Portanto, não presuma que todo diretório será apagado imediatamente após o teste. Resíduos podem permanecer no disco, mas novas execuções não devem reutilizá-los como entrada.

Atenção

Não limpe pastas pessoais

Use somente dados sintéticos criados pelo próprio teste. Não escreva rotinas que percorram ou excluam arquivos de pastas pessoais para “limpar” o cenário: o isolamento deve vir do diretório temporário e dos caminhos controlados.

Verifique seu julgamento

Retenção não elimina o isolamento

Se um diretório temporário ainda existir no disco depois da execução, isso prova que o próximo teste reutilizará seus arquivos.

Independência da ordem

Um teste permanece independente quando cria seus dados sob o próprio tmp_path e passa os caminhos explicitamente ao código testado.

Passo 7 de 7

Consolidar e executar a suíte de integração

Reúna o fluxo e os testes em arquivos locais, execute os três cenários e confirme que a suíte permanece isolada e repetível.

Monte os arquivos locais

Estrutura da prática

Crie uma pasta vazia no seu computador. Dentro dela, crie processamento.py e a pasta tests, contendo test_integracao.py. O exemplo é completo e usa arquivos reais sob o diretório exclusivo recebido por cada teste.

processamento.py

Este módulo lê uma lista JSON, calcula o total e persiste o resumo. A entrada é lida e processada antes da abertura da saída.

python
import json
from pathlib import Path


def carregar_quantidades(caminho: Path) -> list[int]:
    texto = caminho.read_text(encoding="utf-8")
    return json.loads(texto)


def calcular_total(quantidades: list[int]) -> int:
    return sum(quantidades)


def gravar_resumo(caminho: Path, total: int) -> None:
    resumo = {"total": total}
    caminho.write_text(
        json.dumps(resumo, ensure_ascii=False),
        encoding="utf-8",
    )


def processar_arquivo(entrada: Path, saida: Path) -> None:
    quantidades = carregar_quantidades(entrada)
    total = calcular_total(quantidades)
    gravar_resumo(saida, total)

tests/test_integracao.py

Cada teste prepara seu próprio cenário sob tmp_path. O caso de sucesso confere o JSON com a biblioteca padrão; os casos de falha exigem exceções específicas e ausência de saída.

python
import json

import pytest

from processamento import processar_arquivo


def test_processa_e_persiste_total(tmp_path):
    entrada = tmp_path / "quantidades.json"
    saida = tmp_path / "resumo.json"
    entrada.write_text("[7, -2, 12]", encoding="utf-8")

    processar_arquivo(entrada, saida)

    conteudo_persistido = json.loads(
        saida.read_text(encoding="utf-8")
    )
    assert conteudo_persistido == {"total": 17}


def test_falha_quando_entrada_nao_existe(tmp_path):
    entrada = tmp_path / "ausente.json"
    saida = tmp_path / "resumo.json"

    with pytest.raises(FileNotFoundError):
        processar_arquivo(entrada, saida)

    assert not saida.exists()


def test_falha_com_json_invalido(tmp_path):
    entrada = tmp_path / "invalido.json"
    saida = tmp_path / "resumo.json"
    entrada.write_text("[3, 5,", encoding="utf-8")

    with pytest.raises(json.JSONDecodeError):
        processar_arquivo(entrada, saida)

    assert not saida.exists()

Execute e repita a suíte

Observe três níveis de execução

Abra o terminal na pasta que contém processamento.py. Execute primeiro cada cenário, depois a suíte completa e, por fim, repita a execução completa. A repetição deve continuar aprovada porque nenhum teste depende dos arquivos produzidos por outro.

Comandos de execução

Execute os comandos na ordem apresentada.

bash
python -m pytest tests/test_integracao.py::test_processa_e_persiste_total -q
python -m pytest tests/test_integracao.py::test_falha_quando_entrada_nao_existe -q
python -m pytest tests/test_integracao.py::test_falha_com_json_invalido -q

python -m pytest tests/test_integracao.py -q
python -m pytest tests/test_integracao.py -q

Dica

O que conferir

Na execução completa, o resultado esperado é 3 passed. O valor 17 foi definido diretamente no teste para os dados [7, -2, 12], sem chamar a função de cálculo para produzir a expectativa. As duas falhas também verificam que resumo.json não foi criado.

Relate as evidências

Revisão e aplicação final

Execute a suíte no seu computador e relate: o resultado das execuções individual e conjunta; o resultado da repetição; o conteúdo esperado de resumo.json; as falhas exigidas; e por que os testes não dependem de caminhos pessoais, resíduos ou resultados de outros testes.

Escreva pelo menos 120 caracteres (0/120).

Competência consolidada

Resumo

Critérios aplicados

Você verificou uma integração local entre leitura, processamento e persistência, dentro dos limites controlados pelo teste.

  • tmp_path foi solicitado como parâmetro e forneceu um diretório exclusivo para cada teste.
  • Entradas sintéticas conhecidas foram criadas dentro do próprio cenário.
  • O sucesso foi verificado pelo conteúdo JSON persistido, não apenas pela existência do arquivo ou pelo retorno da operação.
  • A expectativa {"total": 17} foi definida independentemente da função de processamento.
  • Arquivo ausente e JSON inválido produziram falhas específicas e reproduzíveis.
  • Cada teste preparou seus próprios recursos, sem caminhos fixos, arquivos pessoais ou dependência da ordem de execução.
  • A suíte verifica componentes locais e o sistema de arquivos real; ela não cobre serviços ou infraestrutura externos.

Tutorial concluído

Parabéns! Você concluiu: Verificar integração com arquivos temporários

Agora você consegue preparar arquivos reais controlados com tmp_path, verificar conteúdo persistido e testar falhas determinísticas mantendo a suíte independente e repetível.

100 XP

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso