Melhorando os testes com o Rspec

No post anterior, utilizamos o excelente Watir (estou gostando mesmo dele), para testar um pouco o Twitter.

Neste iremos melhorar o código dos testes, como foi prometido.

Após a leitura do post, você estará sabendo:

  • O que é o Rspec;
  • Como escrever os seus testes com o Rspec;
  • Porquê utilizar o Rspec é uma boa ideia.

O que é o Rspec?

O Rspec é um framework de testes de unidade, assim como o JUnit. Porém ele vai além de apenas fornece um conjunto de métodos para os seus testes, e nos fornece uma DSL para descrever os compartamentos esperados do sistema[1], ou seja, ao invés, de ter apenas “um monte” de asserts, temos “um monte” de asserts dentro de exemplos executáveis, a diferença é sútil, mas faz um boa diferença.

Watir + Rspec = HAVEFUN

Os testes do último exemplo possuem um código bem ruim. Os problemas maiores dele são:

  • Repetição de código;
  • Testes fortemente acoplados;
  • Mal organizado.

Utilizando o Rspec podemos combater esses problemas. E lembre-se, não é porquê o código é para realizar testes, que ele pode ser feito de qualquer jeito, muito pelo contrário, devemos sim seguir boas práticas, como por exemplo os princípios SOLID.

Vamos agora direto vê como ficam os testes usando o Rspec:

require 'spec_helper'

USERNAME = 'YOUR USERNAME'
PASSWORD = 'YOUR PASSWORD'
MESSAGE = 'Watir rocks!'
MESSAGE_WITH_MORE_THAN_140_CHARACTERS =  "testing characters limit. 140 characters is the  characters limit. Are you pass? not yet? not? not? when are we pass? now? We break the limit!"
TWITTER_REPEATED_MESSAGE = 'Whoops! You already said that...'

describe Twitter::HomePage do

  before(:all) do
    @home_page = Twitter::HomePage.new
    @home_page.visit
    @home_page.login(USERNAME,PASSWORD)
  end

  it "send a message when it is valid" do
    @home_page.type_message(MESSAGE)
    @home_page.tweet
    @home_page.message_exists?(MESSAGE).should be_true
  end

  it "return a error messagem when try to send a repeated message" do
    @home_page.type_message(MESSAGE)
    @home_page.tweet
    @home_page.alert_message_exists?(TWITTER_REPEATED_MESSAGE).should be_true
  end

  it "don't allow to send a message when it contains more than 140 characters" do
    @home_page.type_message(MESSAGE_WITH_MORE_THAN_140_CHARACTERS)
    @home_page.tweet_button_is_disabled?.should be_true
  end

  it "don't allow to send a message when it is blank" do
    @home_page.type_message('')
    @home_page.tweet_button_is_disabled?.should be_true
  end

end

O que achou? Bem melhor que aquela “massaroca“, não é mesmo?

E viu só como o código ficou até mais simples. Prova que fazer da forma correta, é diferente de fazer da forma complicada.

O que mudou?

Antes tínhamos um código com muito repetição, é só olhar os vários ifs e elses para perceber que algo não estava certo. Agora usando o Rspec, temos os próprios métodos dele ao nosso dispor. E como você pode vê, o nosso código é praticamente um texto corrido.

Caso essa seja a primeira vez que você vê um código usando o Rspec, segue uma explicação abaixo sobre ele:

  • Primeiro estamos fazendo require de um helper, que apenas faz require da nossa classe HomePage (mais por organização);
  • No describe estamos passando a classe que iremos testar (Twitter é o módulo e HomePage é a classe) e um bloco (tudo dentro do do até o end lá do final é bloco que estamos passando);
  • O before contém passos que serão executados antes do teste (pré-condições), no nosso caso estamos logando no Twitter, antes de todos os testes. Ou seja, ele é executado apenas uma vez, e não antes de cada teste;
  • Depois temos os nossos exemplos/testes, cada um com uma asserção no final.

O que não mudou

Os nossos testes continuam com um bom nível de acoplamento/dependência, e isso costuma não ser bom. É só observar o segundo teste, ele depende do primeiro para funcionar, caso o primeiro teste falhe, o segundo provavelmente vai falar também.

No entanto, eu acabei optando por manter desta maneira, não por preguiça, mas sim porquê vejo que se o primeiro teste falha, o segundo deve falhar mesmo.

É mais uma escolha por deixar mais simples, embora eu goste da ideia de deixar os testes “atômicos”.

Organização e execução dos testes

Como você deve lembrar, temos a nossa classe HomePage, que ainda vai continuar da forma que está.

Continuamos usando ela, só que agora não temos tudo num mesmo arquivo. Temos agora um projeto, que segue a seguinte estrutura:

  • -> lib
    • -> twitter
      • home_page.rb
  • -> spec
    • -> twitter
      • home_page_spec.rb
    • spec_helper.rb

Resumindo: na pasta lib temos a classe HomePage, que prover os métodos para facilitar a criação e reutilização dos testes, que estão na pasta spec. Ambas as pastas twitter, existem pois podemos criar testes para outro site, e separar ele em outra pasta.

Por exemplo, se a gente for testar o Google, podemos criar uma pasta google, dentro de lib e spec. E aí na primeira ficarão as classes para os nossos testes e na segunda os testes em si. Tá vendo só como fica bem organizado, mesmo quando começarmos a ter muitos arquivos e pastas.

Passada a explicação sobre a organização do nosso projeto, vamos vê o díficil comando para rodar os nossos testes. Basta digitar: rspec spec/twitter/home_page_spec.rb

Só isso mesmo. Os testes serão executados e você verá em seu terminal/prompt o resultado dos testes.

Melhor que isso, só isso:

rspec spec/twitter/home_page_spec.rb -f h > resultado.html

Agora temos o resultado dos testes numa bela página em HTML.🙂

Por que usar o Rspec?

Após mostrar um exemplo sem o Rspec e outro com, deve ter ficado bem clara a diferença das duas abordagens.

Não apenas estamos evitando reiventar a roda, como estamos utilizando um roda muito bem testada e amplamente usada. O Rspec é hoje, a ferramenta número 1 para muitos desenvolvedores Ruby, e mesmo a gente não precisando de muitos recursos que o Rspec pode fornecer, como por exemplo mocks, ele atende muito bem a nossas necessidades, que são básicas. Além disso, deixa os testes muito mais claros, e assim fica mais fácil para você ou uma outra pessoa dá manutenção mais pra frente.

Lógico que ele não é a única boa opção, temos por exemplo, o TestUnit que é muito bom por sinal, e se a gente quiser deixar mais alto nível ainda os nossos testes, podemos usar o Cucumber.

A mensagem que quero passar, é que poderíamos muito bem ter continuado a escrever os nossos testes daquela forma antiga, porém há formas melhores de automatizar os nossos testes. E isso não é sobre fazer “bunitinho” pra publicar num post, e sim a respeito de fazer “bunitinho” para tornar o seu trabalho mais fácil a médio e longo prazo.

O projeto

O projeto do post está disponível no meu Github (a versão 1.1 é a desse post – o link já vai pra ela). Para você utilizar ele, basta fazer clone do projeto (git clone git@github.com:FabricioFFC/watir_tests.git – necessário ter o git instalado).

Com o projeto em mãos, instale o Bundler (gem install bundler) e depois rode o comando bundle install, para instalar o Watir e o Rspec. Não se esqueça, que caso você queira testar usando o Internet Explorer, será necessário alterar dois arquivos: Gemfilehome_page.rb. Em ambos, comente a linha require firewatir e descomente a linha require watir.

Se tiver alguma dúvida ou problema para rodar os testes, só avisar nos comentários. E sugestões, críticas e opiniões sobre o projeto são bem-vindas também.

Até a próxima.

Fique por dentro das novidades, assine o feed do QualidadeBR.

OBS.: Ainda não testei no Windows, só no Ubuntu. Mas não deve ter diferenças. Se alguém encontrar algum problema, avise por favor.

[1] http://blog.davidchelimsky.net/2007/05/14/an-introduction-to-rspec-part-i/

3 comentários sobre “Melhorando os testes com o Rspec

  1. Pingback: links for 2011-03-20 « pabloidz

  2. Pingback: Escrevendo testes melhores com o Watir « QualidadeBR

  3. Pingback: Melhorando os testes com o Rspec | Qualidade de Software

Deixe uma resposta

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