MouseOver Studio

MouseOver Studio header image 2

Melhora consideravelmente teus testes seguindo um simples padrão: um assert por teste

novembro 11th, 2008 por Diego Carrion · 8 comentários

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.

Tags: bdd · tdd

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