Algumas dicas para testes melhores

October 27th, 2008 § 3 comments

O Lucas Húngaro escreveu recentemente sobre a necessidade de abandonar testes quebradiços com uma forma de manter seus testes saudáveis, citando vários exemplos de como isso pode ser feito. Desnecessário dizer, concordo com o que ele disse.

Um conselho dele em particular me parece a melhor consideração sobre o assunto. Falando sobre mocks e stubs, ele diz:

Algumas soluções pra isso são: não utilizar mocks e stubs (o que é um tanto extremista), aumentar o encapsulamento das classes ou aceitar isso e continuar.

Chamo a atenção para a parte final: algumas vezes, você tem simplesmente que aceitar que alguns testes devem ser de certa forma para garantir uma cobertura mais compreensiva.

Dito isso, seguem algumas dicas para testes melhores:

Mocks e Stubs

Uma regra simples que pode ajudar a entender quando usar essas duas técnicas é a seguinte: Se o comportamento esperado deve ser conhecido, use mocks e stubs. Caso contrário, não.

Isso torna fácil perceber que testes de modelos–no caso do Rails, por exemplo–raramente (ou nunca) deve usar essas técnicas. Quando se trata do domínio da aplicação, encapsulamento é uma propriedade básica de sistemas orientados a objetos que não deve ser violada se possível. Obviamente, abstrações vazam; mas isso não deve ser uma desculpa para quebrá-las em testes.

Não teste a abstração imediatamente inferior

Se você está usando Rails, por exemplo, não faz o menor sentido testar a abstração inferior. É muito comum ver testes como:

it "should return all current books" do
  Book.current.proxy_options.should == { :conditions => { :current => true } }
end

Esse tipo de teste verifica se o Rails está funcionando da maneira como deve funcionar e não se o seu código está correto. O resultado é que pequenas mudanças e principalmente a introdução de algum comportamento ortogonal pode quebrar completamente a aplicação enquanto o teste continua a funcionar.

Digamos, por exemplo, que você agora tenha que usar alguma esquema de caching em sua aplicação. No interesse de que a abstração não vaze, você envolve o método acima em alguma abstração que faça isso. O teste acima provavelmente quebrará de imediato, porque está testando a abstração inferior e não o comportamento da aplicação.

O teste correto, nesse caso, seria verificar se a lista retorna é realmente correta, mesmo que isso envolva alguma manipulação de dados que reduza a velocidade do teste.

Use testes de sanidade

Conversamente, é importante também ter alguns testes de sanidade. Às vezes é necessário saber se alguma coisa está declarada, mesmo que a forma final daquela declaração não seja importante.

Um exemplo disso são testes em views. Geralmente, testar se algum conteúdo está aparecendo em uma view é inteiramente desnecessário e pode gerar testes que devem ser refeitos a cada pequena mudança para se adaptar a novas condições.

Mesmo assim, em alguns casos é importante a existência de testes que correm esse risco como forma de testar a sanidade da aplicação; em outras palavras, testar se condições básicas estão sendo supridas.

Não teste nada que não seja público

Uma pergunta muito comum em listas de discussão é como testar métodos privados ou protegidos de uma classe. A reposta geralmente envolve o uso de reflexão e violação de abstrações.

Um exemplo comum seria o código abaixo:

it "should prepare the environment" do
  Manager.send(:prepare_environment)
  Manager.environment.name.should == "development"
end

A resposta correta deveria ser: nunca faça isso. Se seus testes contém alguma necessidade desse tipo, você está violando o encapsulamento e isso indica alguma problema arquitetural mais básico da aplicação. Provavelmente alguma necessidade de separação de dependências que você ainda não identificou.

Nesse casos, funcionalidade básica que envolva código encapsulado pode ser melhor testada pelo seu efeito em outras partes da aplicação.

Cuidado com a ordem dos seus testes

Uma coisa interessante é tentar rodar os seus testes em ordem arbitrária. Existe opções para isso em alguns dos frameworks existentes que podem ajudar a identificar dependências escondidas em seus testes.

Finalizando

Para terminar, esse são apenas alguns dos muitos conselhos possíveis nessa área. Fiquem à vontade para usar a área de comentários do texto para expandir sobre o assunto.

Um conselho final: use seus testes como oportunidades para pensar sobre a sua aplicação. Se você se vê em uma situação em que testar está se convertendo em algo progressivamente mais complicado, alguma coisa está errada na forma como você desenhou seu código. Pare, pense sobre o assunto, e refatore. Seu código e seu tempo agradecem.

Tagged

§ 3 Responses to Algumas dicas para testes melhores"

  • Jeveaux says:

    Muito bom o post, Ronaldo.

    Lendo a parte sobre a ordem dos testes pensei como que com o passar do tempo, mesmo praticando sempre, às vezes cometemos alguns deslizes. A primeira coisa que pensei foi: “Ai caramba, aquele projeto ‘lá’ não pode mudar o ordem”… Preciso arrumar isso

    Abraço,

  • Também é importante lembrar dos testes de conjunto.
    E que, no final, testes com usuários “comuns”, que em nada tem a ver com o desenvolvimento da aplicação, são aqueles que vão pegar os erros que passaram pelos testes unitários e de aderência.

    Muito bom o post :)

  • Sidnei says:

    Excelente matéria. Parabéns.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

What's this?

You are currently reading Algumas dicas para testes melhores at Superfície Reflexiva.

meta