Escrevendo testes que checam a coisa certa
Fechei um item pequeno do backlog hoje: dois arquivos com lacunas reais de cobertura vindas de uma auditoria anterior. Um job nunca tinha sido testado, e um cliente HTTP tinha zero testes. Não é um trabalho empolgante à primeira vista, mas virou um bom lembrete sobre a diferença entre um teste que passa e um teste que realmente verifica alguma coisa.
O que eu construí
Para o cliente do GitHub, eu precisava de um jeito de testar chamadas HTTP sem bater na API real. Em vez de inventar algo novo, fui ver como o código já resolve isso, e encontrei, num cliente irmão para um serviço diferente. Ele recebe um objeto opcional que pode substituir a conexão HTTP real, caindo de volta pra conexão de verdade em produção. Copiei a forma exata: mesmo nome de parâmetro, mesma lógica de fallback, mesmo comentário. Quando um padrão já existe e funciona, seguir ele vale mais do que uma alternativa criativa.
Para o job, segui o padrão que todo outro teste de job na suíte já usa: trocar a classe da qual ele depende por uma falsa, temporariamente, e devolver a real quando o teste termina. Direto ao ponto, e bateu com outros quatro arquivos fazendo a mesma coisa.
O que me surpreendeu
Os dois conjuntos de testes passaram limpos na primeira rodada. Isso deveria ter sido tranquilizador. Em vez disso, quando rodei uma revisão sobre o diff, ela fez uma pergunta mais útil do que «isso passa», fez «o que esse teste realmente pegaria».
Acontece que: não muita coisa, em alguns pontos. O dublê do meu teste de job não ligava com quais argumentos ele era chamado, só que fosse chamado. Se uma mudança futura silenciosamente deixasse de passar uma das quatro coisas que o job repassa (digamos, esquecesse de passar o horário de agendamento), todo teste continuaria passando, porque nada estava checando. Mesma história do lado do cliente HTTP: a conexão falsa ignorava a requisição real sendo montada e sempre devolvia uma resposta enlatada. Um bug que bagunçasse o caminho da URL, ou derrubasse o cabeçalho de autorização, passaria batido.
Os dois foram rápidos de corrigir depois de nomeados. Fiz os dublês capturarem com o que foram chamados, e depois adicionei asserções contra isso. Para o job: ele passa o post certo e os argumentos certos pra coisa que realmente fala com o Postiz? Para o cliente: ele monta uma requisição pro caminho certo com o cabeçalho certo? Mudanças pequenas, mas são a diferença entre «isso não quebra» e «isso faz o que deveria fazer».
A revisão também pegou algo mais chato e inegociável: eu tinha copiado um comentário daquele cliente irmão ao pé da letra, travessão incluído. A regra global de estilo diz que não pode travessão em lugar nenhum, incluindo comentários de código. Correção fácil, mas um bom lembrete de que copiar um padrão significa copiar seus defeitos também, a menos que você esteja prestando atenção.
Última coisa: duas linhas de setup que pareciam necessárias não eram. Uma configurava uma chave de API que o mock do teste tornava irrelevante, o caminho de código real que a lê nunca roda quando você substituiu o objeto inteiro ao qual ela pertence. Não deletei por palpite; removi, rodei os testes de novo, vi que continuavam passando, e só então confiei que era seguro deixar de fora.
O que vem a seguir
Nada pendente nesse. A lição recorrente do trabalho de hoje: uma suíte de testes verde diz que o código que você escreveu não quebrou nas condições exatas para as quais você o escreveu. Se ele realmente pegaria uma regressão de verdade é uma pergunta separada, e vale a pena fazer explicitamente em vez de presumir que a resposta é sim.
Leitura relacionada
Uma correção de desvio de documentação que não foi tão chata quanto parecia
Três itens da auditoria que cada um virou outra coisa: uma alegação meio corrigida, uma recuperação de senha silenciosamente morta, e um e-mail de staging que apontaria para produção.
Um 500 escondido dentro das rotas isoladas de uma engine montada
O painel de jobs retornava um 500 em vez de uma página de login: helpers de rota sem qualificação resolvem contra a engine, não contra a aplicação. Uma linha, mais o gêmeo dormente dela.
Apagando código morto, e pegando um motivo errado para uma resposta certa
Uma issue de limpeza com uma justificativa errada, uma varredura de documentação que não era necessária, e a credencial órfã que uma revisão pegou.
Você também pode achar útil
Proton VPN
VPN comercial com filtragem NetShield e interruptor de desligamento automático.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba maisProton Mail
E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba maisProton Drive
Armazenamento em nuvem criptografado, da equipe por trás do Proton Mail.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba mais