Já faz um tempo que sou apaixonado por especificações executáveis vulgo testes. Constantemente tento melhorar minhas especificações e testes lendo ao respeito e vendo os testes de outras pessoas. Nessa rutina me encontro frequentemente com testes que me deixam muito a desejar e que podem melhorar muito simplesmente seguindo o padrão um assert/expectativa por teste.
Antes de justificar por que eu acho que o padrão deve ser seguido, vou dizer que especificação e teste são para mim duas coisas diferentes, mas são duas coisas que se complementam. Nada melhor para me explicar que com exemplos:
it "should find customers by a given name" do ... end test "customers are found by a given name" do ... end
public void testCustomersAreFoundByAGivenName() {
...
}
Nos três blocos acima, em todos os casos temos um requisito ou especificação do nosso sistema (”os clientes devem ser encontrados dado um nome”) e um código ou teste (”…”) que verifica que esse requisito/especificação esta sendo satisfeito. Podemos chamar o conjunto inteiro de teste mesmo, mas é importante não esquecer de que nele devemos ter uma especificação.
Somente como anedota, tem muitas vezes que baixei o código fonte de algum framework ou api somante para ver os testes e poder saber o que o código pode e não pode fazer. Os testes podem e devem ser muito informativos.
Mas por que estou falando isso? Estou falando isso porque esse comportamento desejado é muito fácil de se alcançar se você seguir o padrão um assert/expectativa por teste. Seguindo esse padrão você vai ter mais blocos de testes, então você vai ter que nomear mais vezes o que o teste ira validar e para não repetir nomes automaticamente você terá que ser mais específico, o que ira criar uma especificação mais detalhada.
Do meu lado esta a ultima Java Magazine, vou pegar o primeiro teste que encontrar na revista como exemplo:
test "enviar relatorio" do
envio_mail = EnvioEmail.new("morena@opensource.com")
assert_true envio_email.enviar
assert_equals envio_mail.texto_mensagem, "Testes executados com sucesso"
assert_equals envio_mail.get_titulo, "Resultado testes"
esperado = Arquivo.new("xpto.zip")
enviado = envio_email.arquivo_mensagem
assert_equals esperado, enviado
end
Antes de aplicar o padrão, qual é o problema com o teste anterior? Imaginemos que estamos executando nosso teste y no terminal aparece que o teste “enviar relatório” falhou. Se eu vejo isso vou pensar que o relatório não foi enviado, mas ele foi! O teste pode ter falhado porque no título se esperava “Resultado testes” e se obteve “Resultado testes.”, com um ponto a mais. O teste não esta somente testando se o relatório foi enviado, esta também testando se ele foi enviado com o título certo, só que o nome não diz isso. Se vendo os testes, nenhum diz que o relatório deve ser enviado com o título certo, posso considera lo como um requisito? Se é um requisito, onde esta escrito? Tenho que ficar analisando dentro dos testes para saber o que o sistema deve ou não fazer? Se não é um requisito, porque esta invalidando o teste?
Aplicando o padrão mencionado no exemplo ele ficaria mais ou menos assim:
antes :todos do
envio_mail = EnvioEmail.new("morena@opensource.com")
end
test "relatório é enviado" do
assert_true envio_email.enviar
end
test "relatório é enviado com o texto certo" do
assert_equals envio_mail.texto_mensagem, "Testes executados com sucesso"
end
test "relatório é enviado com o título certo" do
assert_equals envio_mail.get_titulo, "Resultado testes"
end
test "relatório é enviado com o arquivo certo" do
esperado = Arquivo.new("xpto.zip")
enviado = envio_email.arquivo_mensagem
assert_equals esperado, enviado
end
Não ficou bem melhor?
Agora, supondo que o problema não foi corregido, ao executar os testes vamos receber que o requisito “relatório é enviado com o título certo” não esta sendo satisfeito, mas ao menos sabemos que isso é um requisito e rapidamente podemos identificar que parte do processo “enviar relatório” não esta correto.
Pensando agilmente, esse requisito que não passou pode não representar muito valor para o cliente. O maior valor para o cliente pode estar em enviar o email mesmo e o teste diz que o email esta sendo enviado, pelo que o cliente poderia aceitar o software e não esperar ate que os outros requisitos que não geram tanto valor sejam satisfeitos.
Mais informação sobre o padrão pode ser encontrado aqui nesse post do Jay Fields. Foi o post que me convenceu de seguir esse padrão e desde ai o venho utilizando.
8 respostas ate agora ↓
1 Eduardo Fiorezi // Nov 11, 2008 at 3:16 pm
Então,,,, eu preocuro ficar no meio termo,, Acho que um assert/should por test/spec, fica meio ilegível quando os arquivos são grandes.. Então prefiro fircar no meio terminar e deixar um test mais conciso dependendo da funcionalidade…
É dificil até explicar,, porque é algo que vem muito do dia a dia trabalhando com tests/specs.
Mas excelente artigo.
Abraços,
Eduardo
2 Eduardo Fiorezi // Nov 11, 2008 at 3:20 pm
Nossa… desculpe pelos erros de português…
3 Julio Greff // Nov 11, 2008 at 3:39 pm
Quando comecei com TDD, nem dava muita bola pra isso. Depois li algo a respeito, achei até legal, mas ainda não consegui me convencer a usar apenas um assert por teste… Acho que deve ser algo relacionado com minha mania de diminuir código ao máximo possível =)
Vou tentar me convencer! Até mais!
4 Diego Carrion // Nov 12, 2008 at 5:48 pm
Eduardo, acho que sou a pessoa menos oportuna para criticar erros de português
Julio, concordo com você que diminuir código é muito bom, mas não por isso vamos por tudo num método só né?
É legal separar o código por responsabilidades e que o nome do método explique o que o código esta fazendo. O mesmo acho que deve ocorrer com os testes e o nome explicar o que esta sendo realmente testado.
Obrigado Eduardo e Julio pela participação.
5 Tony Fabeen // Nov 13, 2008 at 1:47 pm
http://giantrobots.thoughtbot.com/2008/11/7/a-critical-look-at-the-current-state-of-ruby-testing
6 Diego Carrion // Nov 13, 2008 at 2:54 pm
Tony, achei os argumentos dados nesse post fracos, vou criar um post contra-argumentando eles.
Obrigado por ter mencionado o link.
7 É um assert por teste um “falso ídolo”? // Nov 13, 2008 at 7:57 pm
[…] RSS ← Melhora consideravelmente teus testes seguindo um simples padrão: um assert por teste […]
8 Is “one assertion per test” a “false idol”? | Diego Carrion // Nov 20, 2008 at 10:04 pm
[…] few days ago I wrote in my portuguese blog an article trying to demonstrate why the “one assertion per test” pattern is an excellent one. If […]
Deixar um comentário