Tenho visto diversas pessoas falando do Shoulda, e algumas que já sentiram o gosto do RSpec e depois também gostaram do Shoulda. Até aí sem problemas. Agora, ao passo que surgem comparações entre RSpec e Shoulda, um sinal amarelo deveria aparecer por aí e deixar algumas coisas bem claras. E este é o objetivo do post.
Primeiro ponto
Em primeiro lugar, a diferença fundamental é: RSpec é totalmente focado no teste de comportamento (Behaviour). Esse é o seu objetivo e a orientação de sua sintaxe. Ok, é possível sim fazer testes no estilo unit/test com RSpec, mas obviamente, não é a intenção ao usá-lo. É como uma implicação na lógica clássica: vou usar RSpec, logo (deveria) me focar em testar comportamento. E, numa implicação, o inverso não é necessariamente verdadeiro.
Resumindo: RSpec é focado em testar comportamento (Behaviour Driven Development). Shoulda não é focado em testar comportamento (Test Driven Development sem o “behaviour” na história), mas tem a intenção de melhorar o test/unit com helpers, macros e contextos. É um açucar sintático que torna os test/unit mais, digamos, pragmáticos e também documentados.
Dito isso, deve-se ter muito cuidado ao compará-los porque são ABORDAGENS e VISÕES diferentes, embora o objetivo de testar seja o mesmo.
Podemos comparar apenas da seguinte forma: Eu gosto mais de RSpec, ou eu gosto mais de Shoulda. Ponto. Qualquer comparação dizendo “este é melhor”, ou “este é pior” deve ser evitada e levar essa diferença fundamental em consideração: “Eu gosto de testar comportamento com o RSpec” ou “Eu prefiro testar no modelo test/unit com Shoulda” são argumentos válidos e não depreciativos entre ambos.
Segundo ponto
Agora, quando eu vejo alguém falando que faz “BDD com Shoulda”, isso me preocupa um pouco. Eu me pergunto: “Será mesmo?”. Confesso, sou um pouco purista no que tange a testar comportamento e estou sempre procurando uma melhor forma de fazê-lo. E já vi opiniões semelhantes por aí.
É possível fazer BDD com Shoulda? Sim, mas de fato não é a tendência ao usar o Shoulda. Vejamos porque.
Suponhamos a seguinte linha, retirada da documentacao do Shoulda:
class Article < ActiveRecord::Base {
named_scope :visible, :conditions => {:visible => true}
}
E o teste para ela com Shoulda:
should_have_named_scope :visible, :conditions => {:visible => true}
Então eu pergunto: testei comportamento ou garanti que existe aquela linha de código no meu Model? Naturalmente, a segunda opção. Não que isso esteja errado, pelo contrário, seu teste tem 100% de cobertura.
Mas, e se minha lógica estiver errada? Digamos que você esqueceu que ao chamar Article.visible não deveria incluir os itens que não foram publicados ainda. Ou seja, você esqueceu uma condição que deveria fazer parte da regra. Mas você tem o teste, então (teoricamente) sua mente está livre do medo de ter errado.
É nesse ponto que entra a idéia de testar comportamento. É mais provável que você descubra esse problema se pensou anteriormente no comportamento que sua busca deveria ter. Note, eu disse que é mais provável, não é garantido que você perceberia isso imediatamente.
OK, e como eu testo o comportamento neste caso?
Estamos lidando com uma busca. Logo, vamos testar o comportamento desta busca simulando-a com exemplos (sintaxe abaixo é RSpec):
describe Article, "being displayed on the website" do
it "should display only visible entries" do
visible = Article.create(:name => "Art1", :visible => true, :published_at => Time.now)
hidden = Article.create(:name => "Art2", :visible => false, :published_at => Time.now)
visible_not_published = Article.create(:name => "Art3", :visible => true, :published_at => nil)
Article.visible.should be_eql([visible])
end
end
Nota: Num contexto real, estou usando o plugin factory_girl, da própria empresa que criou o Shoulda. É ótimo, sugiro o uso.
Simulei alguns cenários e acredito que é mais provável que eu encontre um erro no comportamento dessa forma, pois fui obrigado a formular um exemplo. Quem é acostumado a unit/test geralmente olha essa situação como um pouco de overkill: o que faria em uma linha, demorou bem mais tendo que pensar nos exemplos e na construção do teste em si.
Mas, o foco de BDD é CLAREZA nos testes e não DRY. Nem sempre um teste deve ser DRY.
É claro que é perfeitamente possível fazer isso com Shoulda e outras libs. A questão é: macros como should_have_named_scope induzem a esquecer o comportamento em benefício da simplicidade e rapidez em escrever o teste.
After all, it’s a matter of taste..
Escolher entre Shoulda e RSpec é uma questão de gosto, como eu falei no começo. Ou você gosta de focar seus testes no comportamento de um objeto, ou você prefere utilizar asserções do test/unit.
Para finalizar, volto a dizer que estamos falando aqui de BDD e TDD, e o objetivo aqui não é comparar frameworks nem gerar flames. “Shouldeiros”, não me crucifiquem por favor 
E opiniões são bem vindas sobre isso tudo.
Obrigado!