Aprendendo TDD! Utilizando Dublês de Teste

No posto anterior fizemos o famoso FizzBuzz utilizando os testes como guia e analisando as decisões de design tomadas ao longo do desenvolvimento. No entanto, no mundo real nem tudo consegue ser testado diretamente e são nesses casos que precisamos utilizar os dublês de teste!

O que são dublês de testes?

Precisamos alertar que a conta do usuário vai expirar caso o pagamento do último mês não tenha sido efetuado. Como adicionaríamos testes para o seguinte código?

class Usuario
  attr_reader :ultimo_pagamento
  UM_MES = 60*60*24*30

  def realizar_pagemento()
    @ultimo_pagamento = Time.now
  end

  def deve_expirar_conta()
    @ultimo_pagamento <= Time.now - (UM_MES)
  end
end

Obviamente não conseguimos fazer o pagamento e esperar um mês para verificar se a conta foi expirada, então precisamos utilizar um dublê de teste para fingir a passagem do tempo.

Dublês de testes são mais conhecidos como mocks, mas existem outros tipos. No artigo The Little Mocker, Uncle Bob explica de maneira bem fácil de acompanhar quais são os vários tipos de dublês, incluindo o mock, e quando é o melhor momento para utilizar cada um deles. No próximo post vamos entrar em mais detalhes sobre os diferentes dublês.

Para o código anterior nós vamos utilizar um stub, que permite alterar o comportamento de um método para ignorar sua lógica e retornar um valor específico. O que é exatamente o que precisamos para testar o código anterior, ao invés de Time.now retornar o tempo atual, vamos retornar uma data que permita exercitar o código.

Testes com dublês

A sintaxe para criar stubs e outros dublês muda um pouco de biblioteca para biblioteca, no caso do MiniTest, definimos o método que desejamos substituir o comportamento, o valor que deve ser retornado e o bloco de código onde aquele stub será válido.

require 'minitest/autorun'
require 'minitest/spec'
require_relative '../lib/usuario.rb'

describe Usuario do
  UM_MES =(60*60*24*30)
  it "expira conta quando pagamento nao foi feito" do
    usuario = Usuario.new
Time.stub(:now, Time.now() - UM_MES) do
      usuario.realizar_pagemento()
    end

usuario.deve_expirar_conta.must_equal true
  end
end

Além do tempo existem outras situações onde não queremos utilizar a implementação real dos métodos como por exemplo, chamadas de serviços externos pela rede, leitura de arquivos locais ou até mesmo chamadas ao banco de dados.

A principal vantagem que eu vejo de utilizar dublês ao fazer TDD é que eu consigo isolar melhor os meus testes e não preciso me preocupar muito com a maneira como outros objetos funcionam. Assim posso focar apenas no design do código que estou desenvolvendo e passar pelo ciclo do TDD mais facilmente. No entanto é preciso tomar cuidado para não utilizá-los de maneira errada!

Quando não utilizar

No artigo Mockar ou não mockar, eis a questão,  Fabio Pereira explora bem os malefícios de utilizar muitos dublês de testes no seu código.

Uma das guerras sagradas no desenvolvimento de software é definir o que é um teste unitário, pois algumas pessoas restrigem ao ponto de utilizar dublês para quaisquer outros objetos, isolando a classe que está sendo testada, outros sugerem que até mesmo chamadas ao banco de dados podem ser feitas em testes unitário.

Independente da sua definição de teste unitário, ao utilizarmos um dublê estamos ignorando toda a lógica implementada naquele método/classe em favor de isolar o teste. Caso essa lógica mude o teste não vai saber e é aí onde mora o perigo.

Devido a maneira como ruby lida com objetos, é possível que o método nem sequer exista mas que ainda assim o teste funcione. O código a seguir utiliza um mock para criar um objeto e simular o seu comportamento, mas a asserção é feita sobre o mock.

it "mata um panda" do
  usuario = MiniTest::Mock.new
  usuario.expect :metodo_inexistente, true

  usuario.metodo_inexistente.must_equal true
end

Utilizar dublês é necessário e tem muitos benefícios, como vimos no exemplo de testes com o tempo. No entanto é preciso ficar atento pois podemos utilizar tantos dublês que no final das contas o teste não testa nada, como nesse exemplo anterior.

No próximo post vamos explorar mais sobre dublês de testes e situações onde podemos utilizá-los para nossos testes.

Compartilhe os posts da série Aprendendo TDD! com seus amigos e colegas que também estão buscando aprender mais sobre essa técnica. E acompanhe o blog pois toda semana tem post novo! Dúvidas, sugestões e comentário podem ser feitas aqui no blog ou no twitter em @marcosbrizeno.

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s