Início › Desafios › Desafio 03
O teste que realmente testa, não só cobre
Alcançar 90% de cobertura é fácil: basta chamar o método dentro de um teste e o Salesforce conta as linhas como cobertas, mesmo que você não verifique nada. O problema aparece meses depois, quando alguém muda a regra de negócio por engano, todos os testes continuam verdes e o bug sobe para produção com o selo de aprovado. Este desafio é sobre a diferença entre um teste que executa o código e um teste que prova que o código está certo.
O cenário
Você recebeu uma classe pronta que já roda em produção. Ela classifica contas pelo faturamento anual e
grava o resultado no campo Rating. A regra é simples e o código funciona. O que falta é o
teste, e é ele o seu entregável.
public with sharing class ClassificadorReceita {
// Classifica cada conta pelo faturamento anual (AnnualRevenue):
// maior ou igual a 1.000.000 vira 'Hot'
// maior ou igual a 100.000 vira 'Warm'
// abaixo disso, ou nulo, vira 'Cold'
// Grava o Rating das contas recebidas. Lista nula ou vazia nao faz nada.
public static void classificar(List<Account> contas) {
if (contas == null || contas.isEmpty()) {
return;
}
for (Account c : contas) {
Decimal receita = c.AnnualRevenue;
if (receita != null && receita >= 1000000) {
c.Rating = 'Hot';
} else if (receita != null && receita >= 100000) {
c.Rating = 'Warm';
} else {
c.Rating = 'Cold';
}
}
update contas;
}
}
Repare nas três faixas e nos dois valores de fronteira: exatamente 1.000.000 e exatamente
100.000. É nas fronteiras que os bugs se escondem, e é ali que um teste decorativo passa
sem perceber que a regra foi trocada.
O que você deve construir
Crie a classe de teste ClassificadorReceitaTest, com este contrato
mínimo:
@isTest
private class ClassificadorReceitaTest {
// seus metodos de teste aqui
}
Ela precisa provar que ClassificadorReceita.classificar faz exatamente o que a regra
descreve, e continuar cobrindo a classe inteira.
Regras de aceite
São elas que separam o teste que testa do teste que só cobre:
- Os dados nascem no próprio teste, via
@TestSetup. Nada de@isTest(SeeAllData=true): o teste não pode depender de nenhuma conta que já exista na org, porque na org de outra pessoa esse dado não estará lá. - Existe um assert para cada faixa, incluindo os valores exatos de fronteira
(
1000000e100000). O teste tem que ficar vermelho se alguém trocar>=por>ou trocarHotporWarm. - Um método de teste classifica 200 contas numa única chamada e verifica que todas saíram com o Rating esperado, sem estourar limite de governança.
- Caminho negativo: chamar o método com lista nula e com lista vazia não lança exceção e não dispara DML.
- Conta com
AnnualRevenueem branco termina comoCold, nunca sem Rating nem com erro. - Todo assert compara o valor esperado e carrega uma mensagem. Contar quantas contas foram atualizadas não prova nada sobre a regra.
O que este desafio avalia
- Se você entende que cobertura e teste são coisas diferentes: cobrir linha não é verificar resultado.
- Se você isola o teste do estado da org, criando o próprio dado em vez de confiar no que já existe.
- Se você testa a fronteira da regra, que é onde mora a maioria dos bugs de classificação.
- Se você exercita o método em massa, e não com um registro só.
Travei. Me dá uma direção (sem entregar a resposta)
Quatro perguntas que destravam o desafio:
- Como criar dados que existem só durante o teste, sem tocar na org real e sem repetir o
insertem cada método? Pesquise por "Apex @TestSetup method" e lembre queSeeAllDataéfalsepor padrão, que é justamente o que você quer. - O método faz
updatee não devolve nada. Como conferir o resultado? Depois de chamar, você consulta as contas de novo dentro do teste. Pesquise por "SOQL inside Apex test". - Como escrever um assert que quebra quando a regra muda? Em vez de checar "o Rating não está
vazio", cheque "o Rating é exatamente
Warmpara faturamento de 100 mil". Pesquise por "System.assertEquals message Apex". - Qual Rating uma conta com exatamente
1.000.000deve ter? E uma com999.999,99? Testar os dois lados de cada fronteira é o que separa o teste de verdade do teste decorativo. Procure "boundary value testing".
Para o bloco de 200 contas, procure "Test.startTest stopTest governor limits": isolar a chamada em massa dentro desse par prova que ela cabe sozinha nos limites de uma transação.
Como testar
A classe de teste você roda pelo Developer Console (Test > New Run) ou pela CLI
(sf apex run test). Verde na primeira execução é o mínimo. Mas o critério de verdade deste
desafio não é o teste passar: é ele falhar quando o código está errado. Prove isso
sabotando o método de propósito:
// Prova objetiva: sabote ClassificadorReceita e rode o teste de novo.
// Troque a linha
// } else if (receita != null && receita >= 100000) {
// por
// } else if (receita != null && receita > 100000) {
//
// Agora uma conta com faturamento de exatamente 100.000 cai em 'Cold'
// em vez de 'Warm'. Rode o teste de novo:
// - se ele ficar VERMELHO, ele esta testando a regra de verdade;
// - se continuar VERDE, ele so cobre linha e nao prova nada.
// Desfaca a sabotagem depois de confirmar.
Esse é o experimento que revela a qualidade do teste. Cobertura mede quanto do código rodou; a sabotagem mede quanto do comportamento você realmente prendeu.
Resolveu? O ganho aqui não é a classe de teste: é sair com o hábito de perguntar de todo teste "se eu quebrar a regra, este assert fica vermelho?". Teste que não fica vermelho quando o código erra é falsa segurança, e falsa segurança é pior que teste nenhum.