Shoulda x RSpec: Cuidado nas comparações

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!

This entry was posted on Domingo, Agosto 17th, 2008 at 20:25 and is filed under rails, rspec, ruby. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

11 Responses to “Shoulda x RSpec: Cuidado nas comparações”

  1. Tailor R. Fontela Says:

    Muito bom, parabéns pelo post cara!

    Particularmente prefiro focar no comportamente do que em asserções, acho que descrever comportamento das aplicações nos testes traz um beneficio bem maior para futuras manutenções no código… mas vai do gosto de cada um também :)

    []’s
    Tailor.

  2. Tapajós Says:

    Oi Jony,

    Eu confesso que durante muito tempo eu relutei a idéia do Vinícius Teles de migrar do test/uni para o Rspec pois achava que eu podia fazer testes mais legíveis com TDD.

    Foi preciso a gente começar a escrever specs para a ficha cair e notar que as coisas são bem diferentes nessas duas abordagens embora o propósito de ambas seja a nobre arte de testar. Hoje em dia eu estou usando RSpec e não quero trocar.

    Quando vejo iniciativas como o Shoulda eu fico com a impressão que se trata exatamente do meu pensamento original de apenas tornar os testes mais claros. Esse esforço realmente merece parabéns pois cumpriu muito bem esse papel.

    Honestamente, hoje vejo que são coisas bem diferentes e quero te dar parabéns por esse post pois com certeza vai acabar com muitas dúvidas.

    []’s

  3. RoadHouse Says:

    só uma dica para manter a sanidade quando se usa RSpec: É de bom tom (e mantém a sua sanidade como eu disse), fazer mock do Time.now, porque sua spec pode não passar dependo do horário em que ela foi rodada (imagine teste de borda, onde um artigo expira no segundo seguinte e por algum motivo o rspec demora um pouco mais pra rodar) ;)

    No mais eu continuo usando o RSpec (embora eu tenha curtido muito algumas coisas do shoulda)

  4. Thiago Pradi Says:

    Ótima artigo!

    Na verdade, segundo o próprio site do Shoulda, ele fala que é somente uma coleção de macros/helpers para incrementar o Test/Unit… comparar os dois seria besteira como você falou, até porque, eles são totalmente diferentes…

    Abraço!

  5. Jony dos Santos Kostetzer Says:

    @taylor e @tapajós, grato por compartilharem suas opiniões e experiêncas ;-)

    @roadhouse faz sentido, nesse exemplo rápido não me preocupei tanto, mesmo pq a query seria “maior ou igual” e teoricamente não haveria problema. Mas concordo com o que vc disse, o Time.now pode dar dores de cabeça..

    @thiago exato.. o grande problema é quando não se tem claras essas diferenças, que é a raiz pra comparações erradas ;-)

  6. Jony dos Santos Kostetzer Says:

    @thiago AH! além do mais, outro ponto que esqueci de comentar é que o Shoulda, embora não declaradamente fale de BDD, usa uma notação confusa que pode gerar mais dúvidas. No meu exemplo, por que o método não é assert_have_named_scope ao invés de should_have_named_scope, já que originalmente se usa os assert_* ?

    Entende como isso pode gerar confusão e induzir comparações erradas?

    abraço!

  7. Flávio Granero Says:

    Olá Jony,
    muito esclarecedor seu artigo,
    eu fiz um post recentemente sobre Shoulda, informando que o mesmo era uma maneira de se fazer BDD. Seu texto me esclareceu quanto ao fato e BDD ser uma forma diferente de testar, testando o comportamento das classes.
    Ainda acredito que Shoulda possa ser usado como um passo intermediário para quem usa Test/Unit e pretende usar BDD, mas acha difícil se acostumar com a sintaxe. O uso de blocos contexts presentes no Shoulda ajuda neste caso.
    Abraço.

  8. Thiago Pradi Says:

    @jony até eu mesmo me confundi, realmente, eu acredito que a idéia do projeto foi somente nomes mais claros para os testes…

    Essa história dos testes com should é meio complicada… alguns projetos já estão vindo com os testes com “should” na frente, causando alguma “confusão” para quem vê no começo… o Dan North explica melhor o porquê de aparecerem os should nos métodos de testes… http://dannorth.net/introducing-bdd

    mais realmente, gera uma confusão isso….

    Bom, acredito que cada um testa como achar melhor… eu preferencialmente prefiro BDD com RSpec.. mais o Shoulda é uma boa alternativa, de curva de aprendizado quase 0, para quem quer um Test/Unit, digamos, mais Amigável e com menos “_” :-)

    Abraço!

  9. Carlos Brando Says:

    Ótimo artigo Jony, e muito bem lembrado! Eu confesso que meu perfil é TDD, por isto gosto muito do shoulda. Mas é sempre bom lembrar que não se pode comparar um com outro, são coisas diferentes com objetivos diferentes. Até porque existem projetos parecidos com o shoulda para o rspec também, mas são pouco usados exatamente pelo fato de não serem práticos no rspec.

  10. Lucas Húngaro Says:

    Grande Jony! Saiu o artigo então! :)

    Como conversamos recentemente, também acredito que é uma questão de gosto. No entanto, sempre digo que é possível fazer BDD com Shoulda ou TDD com RSpec. Tudo depende de quem está escrevendo.

    Podemos cair também na questão do purismo: você pode não utilizar os macros do Shoulda e ficar apenas com os contextos, tornando os testes “mais BDD”. Particularmente, gosto de usar ambos e, no exemplo que você citou, conforme conversamos esses dias, eu utilizaria tanto o macro “should_have_named_scope” quanto um bloco should com um teste semelhante ao que você mostrou com RSpec.

    É isso. Parabéns pelo artigo!

  11. Nome do Jogo » Blog Archive » Shoulda 2.0 Says:

    […] Shoulda x RSpec: Cuidado nas comparações […]

Leave a Reply