Ruby

Você está em: Home » Desenvolvimento » Ruby » Benchmark entre RSpec e Shoulda

« Voltar

Benchmark entre RSpec e Shoulda

13 de agosto de 2009 - 16:25


Em um projeto que estou trabalhando atualmente, a suíte de testes (que utiliza Shoulda e Factory Girl) demora aproximadamente 26 minutos para ser executada. Esse tempo de execução é extremamente inaceitável, já que uma das premissas do Test-Driven Development é que sua suíte de testes seja executada o mais rápido possível!

Sem nenhum embasamento, sempre achei que o tempo excessivo se dava ao uso do Factory Girl, devido sua interação com o banco de dados. Hoje, decidi tirar a prova e fiquei surpreso com alguns números obtidos em um benchmark entre RSpec e Shoulda, como você pode conferir abaixo.

Preparando o ambiente

O primeiro passo, foi criar um aplicativo novo com apenas um único modelo chamado Post.

class CreatePosts < ActiveRecord::Migration def self.up create_table :posts do |t| t.string :title t.text :content
  t.timestamps end end
  def self.down drop_table :posts end
end

Antes de realizar o benchmark, foram executados os comandos rake db:migrate e rake db:test:prepare. Depois, foram criados branches específicos para cada um dos testes.

Foram realizados 4 tipos de teste:

  • Shoulda com Factory Girl
  • Shoulda sem Factory Girl
  • RSpec com Factory Girl
  • RSpec sem Factory Girl

Todos os testes acima foram executados no Ruby 1.8.7 (2009-06-08 patchlevel 173) e Ruby 1.9.1 ruby 1.9.1 (2009-07-16 p243 revision 24175) com Rails 2.3.3. Os tempos foram obtidos utilizando o comando time ao executar a rake task padrão com o comando time rake.

Veja abaixo como foram os testes realizados.

Shoulda com Factory Girl

A primeira medição foi feita utilizando Shoulda com Factory Girl. Para criar o objeto, foi utilizada a factory abaixo.

Factory.define :post do |f| f.title "Lorem ipsum dolor sit amet" f.content "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
end
 
class PostTest < ActiveSupport::TestCase context "Post with defaults" do setup do @post = Factory(:post) end
  10_000.times do |i| should "do assertion #{i}" do assert_equal @post.title, "Lorem ipsum dolor sit amet" end end end
  context "Post with custom title" do setup do @post = Factory(:post, :title => "Lorem ipsum dolor sit amet FTW") end
  10_000.times do |i| should "do assertion #{i}" do assert_equal @post.title, "Lorem ipsum dolor sit amet FTW" end end end
end

Shoulda sem Factory Girl

Os testes sem Factory Girl utilizaram a abordagem de se ter um método para criar o objeto.

class PostTest < ActiveSupport::TestCase context "Post with defaults" do setup do @post = create_post end
  10_000.times do |i| should "do assertion #{i}" do assert_equal @post.title, "Lorem ipsum dolor sit amet" end end end
  context "Post with custom title" do setup do @post = create_post(:title => "Lorem ipsum dolor sit amet FTW") end
  10_000.times do |i| should "do assertion #{i}" do assert_equal @post.title, "Lorem ipsum dolor sit amet FTW" end end end
  private def create_post(options={}) Post.create({ :title => "Lorem ipsum dolor sit amet", :content => "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." }.merge(options)) end
end

RSpec com Factory Girl

Para testar o RSpec com Factory Gir, foi utilizado o código abaixo.

describe Post do describe "with defaults" do before do @post = Factory(:post) end
  10_000.times do |i| it "should do assertion #{i}" do @post.title.should == "Lorem ipsum dolor sit amet" end end end
  describe "with custom title" do before do @post = Factory(:post, :title => "Lorem ipsum dolor sit amet FTW") end
  10_000.times do |i| it "should do assertion #{i}" do @post.title.should == "Lorem ipsum dolor sit amet FTW" end end end
end

RSpec sem Factory Girl

E aqui vão os testes escritos para RSpec sem utilizar o Factory Girl.

describe Post do describe "with defaults" do before do @post = create_post end
  10_000.times do |i| it "should do assertion #{i}" do @post.title.should == "Lorem ipsum dolor sit amet" end end end
  describe "with custom title" do before do @post = create_post(:title => "Lorem ipsum dolor sit amet FTW") end
  10_000.times do |i| it "should do assertion #{i}" do @post.title.should == "Lorem ipsum dolor sit amet FTW" end end end
  private def create_post(options={}) Post.create({ :title => "Lorem ipsum dolor sit amet", :content => "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." }.merge(options)) end
end

Test::Unit com Factory Girl

class PostTest < ActiveSupport::TestCase def setup @post = Factory(:post) end
  10_000.times do |i| self.class_eval <<-TXT def test_assertion_#{i} assert_equal @post.title, "Lorem ipsum dolor sit amet" end TXT end
end
 
class PostWithCustomTitleTest < ActiveSupport::TestCase def setup @post = Factory(:post, :title => "Lorem ipsum dolor sit amet FTW") end
  10_000.times do |i| self.class_eval <<-TXT def test_assertion_#{i} assert_equal @post.title, "Lorem ipsum dolor sit amet FTW" end TXT end
en

Test::Unit sem Factory Girl

class PostTest < ActiveSupport::TestCase def setup @post = create_post end
  10_000.times do |i| self.class_eval <<-TXT def test_assertion_#{i} assert_equal @post.title, "Lorem ipsum dolor sit amet" end TXT end
  private def create_post(options={}) Post.create({ :title => "Lorem ipsum dolor sit amet", :content => "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." }.merge(options)) end
end
 
class PostWithCustomTitleTest < ActiveSupport::TestCase def setup @post = create_post(:title => "Lorem ipsum dolor sit amet FTW") end
  10_000.times do |i| self.class_eval <<-TXT def test_assertion_#{i} assert_equal @post.title, "Lorem ipsum dolor sit amet FTW" end TXT end
  private def create_post(options={}) Post.create({ :title => "Lorem ipsum dolor sit amet", :content => "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." }.merge(options)) end
end

Resultados

Antes de mostrar os resultados, quero dizer que fiquei extremamente impressionado com os resultados obtidos com Shoulda no Ruby 1.9.1; houve uma diminuição de pelo menos 5 minutos em relação ao mesmo teste executado no Ruby 1.8.7. No caso do RSpec, não houve diferença significativa.

O Test::Unit saiu em desvantagem nesse benchmark; para adicionar os testes, foi utilizado o método class_eval, que é uma operação bastante dispendiosa.

E se você não aguenta mais esperar pelos números, aqui vão eles:

Ruby 1.8.7 Ruby 1.9.1
Rspec com Factory Girl 1m35.028s 1m10.277s
Rspec sem Factory Girl 1m36.353s 1m11.002s
Shoulda com Factory Girl 8m20.456s 3m33.408s
Shoulda sem Factory Girl 8m35.973s 3m35.687s
Test::Unit com Factory Girl 1m38.559s 1m39.538s
Test::Unit sem Factory Girl 1m38.944s 1m40.026s

Como eu jamais podia esperar, o Shoulda é o problema e não o Factory Girl! Embora eu acredite que a implementação do Shoulda seja infinitamente mais simples que a do RSpec, ela consegue ser muito mais lenta!

Pessoalmente, nunca usei o Shoulda em meus projetos pessoais. E, com certeza, não será agora que irei utilizá-lo!

Se quiser adicionar algum benchmark, veja o código utilizado nestes testes no Github: http://github.com/fnando/benchmark-rspec-shoulda/.

Update: Adicionei os tempos para os testes usando Test::Unit.

Fonte: Simples Ideias

O que você achou deste conteúdo?

  • Bom
  • Ruim
 

  • del.icio.us
  • Digg
  • reddit
  • StumbleUpon
  • Technorati
 

Comentários (0)

Comente

 

Trocar imagem

 

Importante: Os comentários publicados através deste website são de exclusiva e integral responsabilidade de seus autores.

publicidade

Fonte

Simples Ideias

Simples Ideias

Por Nando Vieira

publicidade

IMD Auditoria