Carregando...

quinta-feira, 19 de agosto de 2010

Repita comigo cada teste no seu galho

quinta-feira, 19 de agosto de 2010
Algo que pode dificultar um pouco para quem está iniciando a programar usando TDD ou BDD e conseguir fazer a distinção do que é um teste de unidade de um teste funcional.

O problema que geralmente se encontra é o que o teste funcional pode parecer muito com o seu teste de unidade, mas sem estar mockado.

Isso é normal e não deve ser encarado como uma duplicação do código de teste.

Basta lembrar do objeto dos testes, um teste Funcional responde se determinada funcionalidade esta ok, portanto não usamos mocks mas objetos reais, o que desejamos é validar a interação entre os objetos, esse tipo de teste te responde "você está com problema aqui nessa funcionalidade", o que difere do teste de unidade pois o objetivo dele é validar a lógica interna de sua classe, portanto a resposta de uma falha em um teste de unidade é "você esta com problema na linha x".


Um comentário :

quinta-feira, 12 de agosto de 2010

TDD e o design de sua aplicação

quinta-feira, 12 de agosto de 2010
Ao programarmos é muito comum não termos um escopo muito bem definido do deve ser desenvolvido, embora saibamos como devemos criar os nossos códigos.

Em que TDD ajuda no design da sua aplicação? Simples, ele o mantém limpo a medida que descobre novas funcionalidades.

Suponhamos que estamos usando o estilo de fora para dentro na construção de nossos testes, devemos então começar pela interface do usuário, portanto teríamos o seguinte teste:

public class CadastroClienteTest {
  @Test public void deveriaEmitirMensagemDeAvisoParaClienteEmAtrazoAoSelecionarCliente(){}
}

Esse teste serve de ponto de partida para o seu design lembre-se que aqui você ainda não pensou em acesso ao banco e em nada de services etc..., apenas disse uma funcionalidade que a sua interface deveria ter, ao ir implementando os métodos e usando uma classe para mockar as suas dependências, você vai desenhando o seu código, implementando apenas aquilo que deve ser implementado.

Teriamos o seguinte teste:
public class CadastroClienteTest {
  
  private CadastroClienteManageBean telaCadastro;  
  private FacesMessages facesMessages;

  @Before public void configuraDependencias(){
    facesMessages = Mockito.mock(FacesMessages.class);
    telaCadastro = new CadastroClienteManageBean();
    telaCadastro.setFacesMessages(facesMessages);
  }

  @Test public void deveriaEmitirMensagemDeAvisoParaClienteEmAtrazoAoSelecionarCliente(){
     telaCadastro.selecionarCliente(1);
     Mockito.verify(facesMessages).add(FacesMessage.SEVERITY_ERROR,"cliente em atrazo");
  }
}
e sua respectiva classe:

public class CadastroClienteManageBean {

  private FacesMessages facesMessages;

  public void selecionarCliente(Integer id){
    // deveria ir ao banco
    facesMessages.add(FacesMessage.SEVERITY_ERROR,"cliente em atrazo");
  }
  
  public void setFacesMessages(FacesMessages facesMessages){
    this.facesMessages = facesMessages;
  }

}

Agora reparando neste código perceba que o sistema não está indo até o banco, para de fato trazer o resultado, ai entra algo que acho incrível do TDD, ele te ajuda a ter um design limpo.

vamos agora melhorar o teste, para fins de simplificação não iremos criar um service para o acesso ao banco, vamos conectar diretamente:

public class CadastroClienteTest {
  
  private CadastroClienteManageBean telaCadastro;  
  private FacesMessages facesMessages;

  @Before public void configuraDependencias(){
    facesMessages = Mockito.mock(FacesMessages.class);
    registrosDeClientes = Mockito.mock(RegistrosDeClientes.class);
    telaCadastro = new CadastroClienteManageBean();
    telaCadastro.setFacesMessages(facesMessages);

  }

  @Test public void deveriaEmitirMensagemDeAvisoParaClienteEmAtrazoAoSelecionarCliente(){
     Cliente clienteEmAtrazo = new Cliente();
     clienteEmAtrazo.setEmAtrazo(true);
     Mockito.when(registrosDeClientes.buscarCliente(1)).thenReturn(clienteEmAtrazo);
     telaCadastro.selecionarCliente(1);
     Mockito.verify(registrosDeClientes).buscarCliente(1);
     Mockito.verify(facesMessages).add(FacesMessage.SEVERITY_ERROR,"cliente em atrazo");
  }
}

public interface RegistrosDeClientes {

  public Cliente buscarCliente(Integer id);

}

Repare que o seu teste agora está sugerindo que você tenha um método de busca, uma vez que você tenha terminado o seu teste na tela, uma abordagem seria descer o nível e pegar todas as classes que você mockou no teste da interface e agora ir implementando o teste para as camadas mais baixas.

TDD ajuda a melhorar o design, fazendo você programar aquilo que você precisa implementar, ao invés de ficar criando métodos para classes que você acha que irá precisar.

O método usado aqui baseasse no teste de fora para dentro, onde fomos construindo um teste para a interface e mockando os objetos das camadas abaixo, e posteriormente deveríamos implementar os testes das camadas mais baixas, com os dados que coletamos dos mocks da camada superior.

Em resumo o mock te sugere o que pode ser necessário que você tenha que implementar, caso não tenha usado ainda TDD, faça um teste e se esforce, pois realmente vale a pena.


Nenhum comentário :