Tag Archives: tdd

Classes testáveis não “buscam”, mas sim “recebem”

TL;DR: Se você quer testar sua classe por meio de teste de unidade, essa classe não deve conter código de infra estrutura (como acesso a banco de dados, e etc), e ela também deve receber toda outra informação ou dependência necessária por meio de construtores ou parâmetros de métodos — a classe nunca deve buscar a informação diretamente ou instanciar uma dependência. Dessa forma, ela será facilmente testável por meio de testes de unidade.

Regras de negócio, no fim, nada mais são do que um monte de ifs e fors juntos. Portanto, deveríamos ser capazes de sempre testá-las por meio de simples testes de unidade. No entanto, às vezes nós dificultamos isso.

Veja o código abaixo. Nele, o FiltroDeFatura pega a lista de todas as faturas que está no banco de dados, e passeia por elas, guardando as que tem valores menor que 2000.

O código é simples, mas pense que ele poderia ser um pouco mais complicado. Portanto, precisamos testá-lo. A questão é: como? Afinal, não conseguimos escrever um teste de unidade pra ela; afinal é impossível executar o método filtra() sem passar por um banco de dados.

Essa é um tipo de código bastante comum nas aplicações por aí. O desenvolvedor sabe que não pode sair misturando SQL no meio de regra de negócio, e corretamente, coloca isso dentro do DAO. No entanto, ele instancia o DAO diretamente na classe, fazendo com que não seja possível executar a regra de negócio, sem passar pelo banco de dados.

E passar pelo banco de dados, na maioria das vezes, não é boa ideia. Escrever o teste é mais difícil (afinal, precisamos fazer INSERT dos dados no começo, DELETE depois, garantir o schema do banco, e etc), e mais demorado. E, aliás, não deveríamos precisar do banco de dados, para testar a simples regra de filtro de fatura.

A solução pra isso é mais fácil do que parece. Se você tem uma classe que contém regras de negócio, essa classe deve apenas conter regras de negócio. Ou seja, ifs e fors. Se sua regra de negócio precisar de alguma informação que venha de uma outra classe qualquer (seja um DAO, seja outra coisa), ela nunca deve “buscar” essa informação, mas sim “recebê-la”.

Ou seja, nesse código em particular, ou passamos a List<Fatura> para o método filtra(), ou passamos o FaturaDao pelo construtor. Veja:

Dessa forma, com o DAO sendo recebido pelo construtor da classe, conseguimos simular seu comportamento durante o teste, por meio de mock objects. E agora sim, nada de depender do banco para fazer um teste tão simples.

Portanto, guarde essa regra: se sua classe é uma classe que contém regras de negócio, ela nunca pode buscar as informações ou dependências que precisa por conta própria; ela deve sempre recebê-las.

Ah, essa ideia tem um nome bonito, inclusive: chama-se inversão de controle. Ou seja, “invertemos” a maneira tradicional de programar, que é sempre buscar pela dependência. Agora, alguém nos dá a dependência. Você pode ler mais sobre isso no meu livro de orientação a objetos e SOLID.

Montando cenários em testes de sistema

TL;DR: Crie serviços web para montar os cenários que você precisa em seus testes de aceitação.

Montar cenários é sempre a parte mais chata em qualquer teste, seja ele manual, de unidade, de integração ou de sistema. O pior é que, quanto mais o teste é parecido com o do mundo real, mais difícil é. No teste de unidade, você tem uma classe, geralmente pequena, e que lida com poucas outras classes. Montar o cenário é razoavelmente fácil; você instancia duas ou três classes e pronto. Mas e quando o teste é de sistema? Como fazer para testar a tela de Nota Fiscal, se para isso, precisamos de um Cliente, Produto e Orçamento cadastrados?

A primeira opção é fazer com que o próprio teste seja responsável por navegar pelas telas anteriores e montar os cenários. Ou seja, antes de ir pra tela de nota fiscal, o teste passeia pela teste de clientes, e cadastra um por lá. Depois vai pra tela de Produto e cadastra um por lá. A mesma coisa com um Orçamento, para aí sim conseguir testar a Nota Fiscal. O problema disso é que absurdamente demorado passear por todas essas telas. E a chance de você repetir código entre as várias baterias de teste é ainda maior.

Nesse momento, meu coração diz que a melhor solução é fazer com que a aplicação Web contenha um conjunto de serviços web, prontos para montar o cenário que a aplicação quiser.

  • Precisa de um Cliente? O teste faz um post para /ws-testes/clientes, com o Cliente desejado.
  • Precisa de um Orçamento? O teste faz um post para /ws-testes/orcamentos.
  • Precisa de um Estado (e não existe tela de estado?) Não tem problema, tem o /ws-testes/estados.

Dessa forma, fica fácil. No código do teste, você faz uso de Test Data Builders para rapidamente montar esses objetos, e simplesmente os envia para a aplicação. Fazer serviços web simples, que recebem basicamente entidades, também é fácil, e seu framework MVC deve fazer isso quase que automático.

Além disso, porquê não ter também o /ws-testes/limpa ? Precisamos limpar nosso banco de dados antes de cada teste, para que um teste não influencie o outro.

Apesar de parecer pouco produtivo, na prática, os Test Data Builders usados são os mesmos que você já usa nos seus testes de unidade. E se você tem uma infraestrutura razoável, fazer serviços web é geralmente mais simples do que escrever a navegação nas funcionalidades ao redor, que você precisaria escrever de qualquer jeito.

Fuja dos XMLs malucos do DBUnit ou mesmo de testes de sistema que precisam navegar por 30 telas antes da sua. Dá trabalho? Claro que dá… Mas testar software é trabalho, não é?!

Para melhorar meu design, preciso mesmo fazer o teste antes?

Já comentei bastante sobre os efeitos que a prática de TDD tem no projeto de classes. Meu livro, aliás, é totalmente focado nisso. No entanto, algo que não comentei nele, porquê provavelmente só soube transformar isso em palavras há pouco tempo, é que não me importo muito se o teste é escrito antes ou depois. Ué, como assim!?

Deixe-me explicar. Não é a “prática de TDD” que faz seu projeto de classes melhorar, mas sim, o que você consegue ver de problemas ao olhar para o código do seu teste. Ou seja, é o teste que te mostra o problema. Se ele é escrito antes ou depois, tanto faz.

Obviamente, se você deixar para escrever o teste 1 semana depois de escrever a classe, na hora em que ler o feedback do teste, talvez seja tarde demais pra refatorar — tarde, no sentido, de caro, afinal você provavelmente precisará mudar em muitos pontos diferentes.

No entanto, se você gastar 15 minutos no código, 15 minutos no teste, 15 minutos no código, 15 minutos no teste…. o feedback será o mesmo! Afinal, para pensar no design, a implementação depende do teste e o teste depende da implementação; a ordem em que você faz não ter dará mais ou menos retorno.

O teste é só um rascunho do seu projeto de classes. E o importante não é ter um rascunho, ou mesmo começar por ele, mas sim rascunhar com frequência.

 

Mockar ou não mockar?

Com toda essa discussão do “Is TDD Dead?”, criada pelo DHH, as pessoas começaram a se perguntar se devem ou não fazer uso de mocks. Apesar do DHH ter sido infeliz no post polêmico, a discussão sobre mocks que ele levantou é bem importante. Tanto é que eu e o Hugo Corbucci fizemos uma palestra dedicada ao uso de mock objects, ano passado, na Agile Brazil.

Nela, discutimos as vantagens e desvantagens de usar ou não usar mocks, quando usar, quando não usar, e etc. Apesar da gravação não ter sido das melhores, é possível aprender bastante com ela.

Espero que gostem!

Mockar ou não mockar? – Hugo Corbucci e Mauricio Aniche from Agile Brazil on Vimeo.

Bate papo sobre TDD na Caelum

Há alguns meses atrás, organizei na Caelum um encontro sobre TDD. Nela tivemos a participação do Anderson Parra, falando sobre Fixture Factory (que divulgarei em breve também!), e depois um bate papo sobre pontos gerais de testes e TDD.

Abaixo segue o vídeo com a discussão na íntegra:

Se você gostou da discussão, não deixe de ver meu livro ou os cursos online do Alura sobre o assunto.

A quantidade de asserts em um teste indica algo? (CSMR2013)

Em março, apresentei um pequeno pedaço da minha pesquisa de doutorado no CSMR2013, em Gênova. O CSMR é uma conferência voltada para trabalhos que discutem manutenção e evolução de software.

Meu trabalho discute a relação entre a quantidade de asserts e a qualidade do código de produção. Será que o desenvolvedor faz uso de mais de 1 assert por teste porque o código de produção é complexo? É mais ou menos essa a pergunta que o trabalho visa responder.

No fim, acabei encontrando que a quantidade de asserts unicamente não indica nada: os desenvolvedores usam um número arbitrário de asserts mesmo com o código sendo simples. Mas algo interessante emergiu: se ao invés de contar a quantidade de asserts, eu contar a quantidade de diferentes objetos que recebem uma asserção e fizer a mesma comparação, isso sim indica que o código de produção pode ser mais complicado do que a média.

Em código, pra ficar mais fácil de entender:

assertEquals(“esperado”, a.getAlgumaCoisa());
assertEquals(“esperado2″, a.getAlgumaOutraCoisa());

Veja que estou fazendo 2 asserts, mas sempre no mesmo objeto “a”. Agora:

assertEquals(“esperado”, a.getAlgumaCoisa());
assertEquals(“esperado2″, b.getAlgumaOutraCoisa());

Veja que tenho 2 asserts em 2 objetos diferentes: “a” e “b”. Nesse caso, os métodos “getAlgumaCoisa()” e “getAlgumaOutraCoisa()” podem estar mais complicados do que deveriam. Portanto, acabei propondo o mau cheiro de teste que é “Mais de Uma Instância de Objeto Recebendo Asserção”. Repare nesse padrão, pois ele pode indicar problemas no seu código de produção.

Você pode ler o paper completo aqui se preferir! :)

Agile Tour 2011 em Poços de Caldas

Esse mês tive o prazer de fazer a palestra de abertura do Agile Tour Poços de Caldas 2011.

A palestra foi bem introdutória. Discuti sobre testes automatizados e TDD. Minha ideia maior foi motivar os participantes a escreverem testes automatizados, a conhecerem TDD, e a perceberem que dá pra fazer isso de maneira divertida! 😉

Seguem meus slides!

Testando datas (e métodos estáticos)

Muitas pessoas me perguntam como escrever testes de unidade de classes que lidam com datas. E, geralmente o problema está em como testar classes que usam a data/hora atual.

Esse problema acontece pois grande parte das APIs que lidam com datas, tanto no mundo .Net quanto no mundo Java, fazem uso de métodos estáticos. Por exemplo:

DateTime.Now // C#
Calendar.getInstance() // Java

Generalizando o problema, a dificuldade nao é testar datas, mas sim qualquer classe que faz uso de métodos estáticos. Por exemplo, como escrever um teste para o método abaixo?

public int DiasEntreHjEAData(DateTime data) {
  return (DateTime.Now - data).TotalDays;
}

A propriedade Now sempre irá devolver a data corrente, dificultando assim a escrita do teste; como escrever um teste onde o cenário muda o tempo todo?

Não conseguir simular o comportamento do método Now, e esse eh um dos problemas de usar métodos estáticos: dificulta o teste das classes que os utilizam (além de não permitir o uso decente de polimorfismo, mas isso é uma outra discussão…)

Para resolver esse problema, precisamos deixar de usar métodos estáticos. Mas e como fazer com as APIs que já existem, e não podemos mudá-las, como é o caso da API de DateTime?

Isso não nos impede de criarmos uma abstração em cima disso! Veja o código abaixo:

public interface Relogio {
  DateTime Hoje();
}

public class RelogioDoSistema : Relogio {
  public DateTime Hoje() {
    return DateTime.Now;
  }
}

Veja que criamos a interface Relogio, que abstrai o problema de calcular a hora atual. Nosso método acima agora, em vez de invocar o método estático, faz uso da nova abstração:

public class Algoritmo {

  // recebido pelo construtor
  private Relogio relogio;

  public int DiasEntreHjEAData(DateTime data) {
    return (relogio.Hoje() - data).TotalDays;
  }
}

Pronto. Veja agora que testar essa classe é facil. Basta passarmos um mock e simular o comportamento esperado do Relogio.

Resumindo, métodos estáticos dificultam a escrita de testes de unidade. Para resolver isso podemos: evitar a escrita de métodos estáticos, ou criar abstrações que escondem esses métodos. Nao é feio criar abstrações como a Relogio; feio é não testar! :)