AULA 31 / 61 · ACESSO GRATUITO

Uma unidade por vez sem perder o todo

Graciliano TolentinoEngenharia Caracol · Edição 2.0
Nesta aula
  1. Foco é delimitar a mudança
  2. Cartão de trabalho preenchido
  3. Como atravessar as fronteiras
  4. Prova real de uma fronteira
  5. Comparar três evidências
  6. Um registro de integração que cabe ser auditado
  7. Erros e reparos
  8. Exercício com resolução
  9. Leitura técnica relacionada

Foco é delimitar a mudança

Uma unidade de trabalho é uma mudança pequena com fronteiras e resultado verificáveis. Ela não precisa coincidir com um arquivo. Corrigir a seleção de casos ativos pode exigir uma função e dois testes, enquanto alterar uma mensagem pode envolver o HTML e o JavaScript da página. A unidade fica pequena quando sua decisão central pode ser explicada e sua consequência pode ser observada, não quando possui arbitrariamente poucas linhas.

O risco do trabalho por unidades é encerrar cada peça isoladamente e descobrir tarde que elas discordam. O servidor pode devolver um objeto enquanto a página espera uma lista. O teste pode criar um caso válido que o arquivo real nunca permite. Integrar significa atravessar essas fronteiras com os contratos efetivos. Não significa usar informações pessoais ou dados de produção. Nossa Oficina usa dados sintéticos representativos e serviços locais reais.

Cartão de trabalho preenchido

CampoUnidade U-ATIVOS
ObjetivoNão revelar casos inativos no catálogo público.
Entrada conhecidaArquivo data/casos.json validado.
Arquivos a inspecionarsrc/catalogo.mjs, src/servidor.mjs, public/app.js e respectivos testes.
Mudança inicialmente autorizadaSeleção do catálogo e teste de regressão; ampliar escopo somente com justificativa.
PreservaçõesFormato público, estados vazio/erro, navegação por teclado e dependências externas zero.
FronteirasArquivo para função; função para resposta HTTP; resposta para interface.
ConclusãoTestes aplicáveis aprovados e fluxo público observado; limites registrados.

Inspecionar não é autorização automática para alterar. A lista permite compreender os consumidores antes da mudança. Se o formato da resposta precisar mudar, a unidade deixa de ser uma correção local: é necessário atualizar explicitamente os consumidores e os testes de contrato.

Como atravessar as fronteiras

  • Confirme o estado anterior e registre a versão que será modificada. Execute a validação atual para não atribuir falhas antigas à nova mudança.
  • Teste a regra em memória com um ativo e um inativo. Esse teste rápido localiza problemas na decisão de seleção.
  • Execute os testes do servidor, que fazem uma requisição HTTP ao servidor local de teste e conferem a resposta. Não substitua essa prova por uma resposta fabricada.
  • Inicie a aplicação com npm start dentro de pratica. Abra http://127.0.0.1:3000 e confira o catálogo, o estado vazio e o estado de erro conforme os roteiros.
  • Interrompa a execução ao terminar e registre o que foi observado. Uma inspeção manual pendente deve permanecer pendente, mesmo quando todos os testes automáticos passaram.

Prova real de uma fronteira

Este módulo de teste completo usa criarServidor e um arquivo temporário de dados sintéticos. É um exemplo adicional para tests/servidor.test.mjs; ao integrá-lo, reúna imports existentes uma vez. O servidor escolhe uma porta livre porque listen recebe zero. await aguarda a escuta e a resposta; finally fecha recursos mesmo quando uma asserção falha.

javascript
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { once } from 'node:events';
import { criarServidor } from '../src/servidor.mjs';

test('integra arquivo, catálogo e resposta HTTP', async () => {
  const pasta = await mkdtemp(join(tmpdir(), 'caracol-livro-'));
  const arquivoDados = join(pasta, 'casos.json');
  const servidor = criarServidor({ arquivoDados });
  try {
    await writeFile(arquivoDados, JSON.stringify([
      { id: 'a', titulo: 'Ativo', descricao: 'Exemplo A', ativo: true },
      { id: 'b', titulo: 'Interno', descricao: 'Exemplo B', ativo: false }
    ]));
    servidor.listen(0, '127.0.0.1');
    await once(servidor, 'listening');
    const base = `http://127.0.0.1:${servidor.address().port}`;
    const resposta = await fetch(`${base}/api/casos`);
    assert.equal(resposta.status, 200);
    assert.deepEqual(await resposta.json(), [
      { id: 'a', titulo: 'Ativo', descricao: 'Exemplo A' }
    ]);
  } finally {
    if (servidor.listening) {
      await new Promise((resolve, reject) => {
        servidor.close(erro => erro ? reject(erro) : resolve());
      });
    }
    await rm(pasta, { recursive: true, force: true });
  }
});

O resultado esperado é HTTP 200 e um único objeto público, sem o caso b e sem a propriedade ativo. O teste exercita arquivo, seleção e serialização reais. Não abre uma página nem executa o JavaScript do navegador; essa limitação impede chamá-lo de prova completa da interface.

Comparar três evidências

EvidênciaO que demonstraO que ainda falta
Teste da função com lista em memóriaA decisão local seleciona apenas ativos nesse caso.Leitura do arquivo, serialização HTTP e comportamento no navegador.
Teste do servidor com dados sintéticosO caminho HTTP exercitado respeita o contrato esperado.Renderização e interação com teclado na interface real.
Roteiro manual no navegadorOs passos efetivamente executados produziram o resultado registrado.Cobertura de outros navegadores, tecnologias assistivas e cenários não executados.

Um mock é um substituto controlado de uma dependência. Ele ajuda a produzir uma falha rara de maneira repetível. Se o teste substitui o servidor inteiro por uma função que sempre devolve sucesso, ele não verifica a integração HTTP real. Também não deve ser descartado: ele responde a outra pergunta. Declare exatamente onde começa e termina cada prova.

Um registro de integração que cabe ser auditado

Modelo preenchido de plano, ainda sem execução: unidade U-ATIVOS; requisitos REQ-001/REQ-002; arquivos afetados identificados no diff; entradas ativo e inativo; expectativa de somente ativo na resposta e na página; comandos npm test e npm run validate; roteiro de navegador e teclado a executar; limite de dados sintéticos e servidor local. Após executar, acrescente o resultado observado e a referência ao log. Antes disso, o campo resultado permanece “pendente”, e não “aprovado previsto”.

O gate integrado exige que as fronteiras obrigatórias desse escopo funcionem, que falhas impeditivas tenham sido resolvidas e que exceções não impeditivas tenham decisão explícita da autoridade definida. Atualize a rastreabilidade da unidade para não manter M6 baseado em um contrato que a alteração invalidou. Uma mudança relevante reabre a evidência afetada; o simples passar dos dias só a invalida quando houver política de validade.

Erros e reparos

  • Arquivo correto, fluxo quebrado: examine o formato recebido por cada consumidor e acrescente uma prova na fronteira que falhou.
  • Mock que vira dependência definitiva: conecte o contrato real antes do gate integrado e mantenha o mock apenas no teste que necessita dele.
  • Mudança colateral no estilo ou nas rotas: retire-a do diff ou abra outra unidade com objetivo e autorização próprios.

Exercício com resolução

Fornecido: o teste da função passa; o teste HTTP recebe uma lista correta; no navegador aparece “Catálogo indisponível”, pois a página tenta ler resposta.itens, mas a rota documentada devolve uma lista diretamente. O autor marcou M6. Qual decisão deve ser tomada?

Ver solução comentada

Resolução: a integração não foi comprovada; M6 não é sustentado. Confirme primeiro qual contrato foi aprovado, corrija o consumidor incompatível e proteja a fronteira com teste ou roteiro específico. Depois repita o fluxo. A rubrica exige localizar a divergência, preservar o formato aprovado, diferenciar as provas já válidas da prova ausente e manter o estado pendente até nova execução. Acrescentar “mais contexto à IA” sem reparar o contrato não resolve o defeito.

Leitura técnica relacionada

S09: Fowler, Continuous Integration, especialmente a integração frequente e a construção autoverificável. S19: Node.js, HTTP server e test runner, para as fronteiras reais exercitadas no projeto.

Fontes relacionadas

Consulte os limites e as seções de apoio de cada referência.

S09 S19
Conseguiu explicar o que aprendeu?

Tente o exercício antes de consultar a solução. Marque a aula para organizar sua leitura.

A conclusão desta leitura não equivale a certificação ou aceite de um projeto real. Teste os exemplos no escopo indicado e registre as limitações.