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! 🙂

3 thoughts on “Testando datas (e métodos estáticos)

  1. Marcos Pereira

    Olá Aniche,

    Uma solução talvez mais simples para C#, seria usar o framework de testes Moles.
    Para o seu exemplo:
    “Emular” a data na sua classe de teste: MDateTime.NowGet = new DateTime(2012,3,5);

    // O código abaixo não precisa mudar.
    public int DiasEntreHjEAData(DateTime data) {
    return (DateTime.Now – data).TotalDays;
    }

    Quando você chamar esse método no seu teste, o método estático DateTime.Now vai retorna 5/3/2012.
    Além de conseguir usar Moles nas classes do .Net, você também pode usar nas suas classes.

    Abraço.
    Marcos.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *