7 coisas que você precisa conhecer no RSpec

O RSpec é um framework bastante completo e, por isso mesmo, muitas coisas são desconhecidas por grande parte dos desenvolvedores. Neste artigo, você conhecerá 7 coisas que irão mudar a maneira como você utiliza o RSpec.

Subject

O RSpec possui um método muito útil chamado subject, que retorna uma instância da classe que está sendo utilizada como contexto do exemplo.

1.describe User do it { should_not be_admin }
2.end

A grande vantagem desta abordagem é que você aumenta consideravelmente a legibilidade de suas especificações. Mas você não precisa utilizar apenas o contexto especificado no métododescribe; se quiser, você pode definir o seu próprio!

1.describe User do subject { User.new(:admin => true) } it { should be_admin }
2.end

Quando outros tipos de objetos (como módulos ou strings) são passados ao método describe, ele irá retornar o próprio objeto.

Message expectation

O método stub_chain

Sempre que você precisar fazer uma chamada encadeada e quiser verificar o último valor, utilize o método stub_chain. Ele permite transformar um bloco como este

1.describe "Mocks" do before do @user = mock() @things = mock() @recent = mock()
2.@user.stub!(:things).and_return(@things) @things.stub!(:recent).and_return(@recent) @recent.should_receive(:count).and_return(100) end
3.it "should return the recent things count from an user" do @user.things.recent.count.should == 100 end
4.end

em uma coisa bem mais simples como esta

1.describe "Mocks" do before do @user = mock() @user.stub_chain(:things, :recent, :count).and_return(100) end
2.it "should return the recent things count from an user" do @user.things.recent.count.should == 100 end
3.end

O método and_return

Você alguma vez precisou acessar um stub mais de uma vez e queria que ele retornasse diferentes valores em cada chamada? Veja este exemplo.

1.require "open-uri"
2.
3.class Dice API_URL = "http://www.random.org/integers/?num=1&;min=1&max=6&col=1&base=10&format=plain&rnd=new"
4.def roll open(API_URL).to_i end
5.end

Toda vez que o método roll for chamado, ele irá fazer uma requisição diferente ao http://random.org. Imagine que por algum motivo você precisasse retornar diferentes valores toda vez que o método open você invocado. Tudo o que você precisa fazer é retornar mais de um valor com o método and_return.

1.describe Dice do before do subject.should_receive(:open).and_return("1", "4", "2") end
2.it "should not cache request" do subject.roll.should == 1 subject.roll.should == 4 subject.roll.should == 2 end
3.end

O método with

O RSpec disponibiliza uma série de métodos que podem ser usados em conjunto com o métodowith. Veja alguns exemplos:

01.module Echo extend self
02.def echo(*args) args.inspect end
03.end
04.
05.describe Echo do # with any kind of argument specify("anything") { subject.should_receive(:echo).with(anything) subject.echo(1) }
06.# with hash containing values specify("hash_including") { subject.should_receive(:echo).with(hash_including(:say => "hello")) subject.echo(:say => "hello") }
07.# with an instance of String specify("instance_of") { subject.should_receive(:echo).with(instance_of(String)) subject.echo("hello") }
08.# with an object that responds to some methods specify("duck_type") { subject.should_receive(:echo).twice.with(duck_type(:<<)) subject.echo(Array.new) subject.echo(String.new) }
09.end

Para ver mais exemplos, acesse https://gist.github.com/45b97f90a83c8acf3f29.

before e after globais

Muitas vezes precisamos preparar nosso ambiente antes de executarmos nossos testes. Quando isso precisa ser feito em mais de uma especificação, você pode diminuir a duplicação de código utilizando blocos globais.

No seu arquivo spec_helper.rb, você pode utilizar os métodos append_before,append_after_prepend_before e prepend_after.

1.Spec::Runner.configure do |config| config.prepend_after { `rm -rf some/path` }
2.end

Pending

Em vez de comentar temporariamente exemplos que você não quer que sejam executados, você pode utilizar o método pending. O método pending pode ser utilizado nos blocos de before. Assim, todos os exemplos daquele contexto de describe serão automaticamente marcados como pendente.

1.describe "Pending examples" do before do pending end
2.# lots of examples
3.end

Você também pode deixar apenas um exemplo pendente.

1.describe "Pending examples" do it "should be pending" do pending "need to working on it" Env.setup! end
2.end

Ou apenas uma parte dele.

1.describe "Pending examples" do it "should be pending with a block" do pending("need to working on it as well") do Env.setup! end end
2.end

Uma outra alternativa (que não é deixar como pendente mas sim desabilitado) é utilizar o métodoxit em vez de it.

1.describe "Pending examples" do xit "should be pending with alias" do Env.setup! end
2.end

Matchers personalizados

Sempre que você perceber que está repetindo um padrão na hora de escrever seus exemplos, automatize o processo criando novos matchers. O RSpec possui duas maneiras diferentes de fazer isso. A mais simples delas é utilizando o método simple_matcher. Crie um módulo chamadoTheAnswerMatchers para adicionarmos novos matchers.

1.module TheAnswerMatchers def be_the_answer simple_matcher do |given, matcher| # save some typing the_answer = "the Answer to Life, the Universe, and Everything"
2.matcher.description = "be #{the_answer}" matcher.failure_message = "expected #{given.inspect} to be #{the_answer}" matcher.negative_failure_message = "expected #{given.inspect} not to be #{the_answer}" given == 42 end end
3.end

Agora, basta fazer com que o RSpec reconheça esses novos matchers; é só incluir o módulo.

1.Spec::Runner.configure do |config| config.include TheAnswerMatchers
2.end

E para escrever seus exemplos, você pode usar o matcher be_the_answer:

1.describe "The Answer to Life, the Universe, and Everything" do specify { 42.should be_the_answer } specify { "the wrong answer".should_not be_the_answer }
2.end

Finalizando…

Como você pode perceber, é bem simples escrever exemplos melhores no RSpec. Se você olhar as specs do RSpec, encontrará bastante coisa legal que você normalmente não veria (porque tem muita coisa para ler) no RDocs.

Fonte: http://wmonline.com.br/desenvolvimento/ruby/7-coisas-que-voce-precisa-conhecer-no-rspec

Deixe um comentário