Skip to main content

Properly testing Rails 3 scopes

·286 words·2 mins· ·
Ruby on Rails Rails Rspec Rails3 Scope Named_scope
Ariejan de Vroom
Author
Ariejan de Vroom
Jack of all Trades, Professional Software Craftsman

The content of this post is no longer correct. Please read this article for details.

Testing scopes has always felt a bit weird to me. Normally I’d do something like this:

class Post < ActiveRecord::Base
  scope :published, where(:published => true)
  scope :latest, order("created_at DESC")
end

describe Post do
  context 'scopes' do
    before(:all) do
      @first = FactoryGirl.create(:post, :created_at => 1.day.ago, :published => true)
      @last  = FactoryGirl.create(:post, :created_at => 4.day.ago, :published => false)
    end

    it "should only return published posts" do
      Post.published.should == [@first]
    end

    it "should return posts in the correct order" do
      Post.latest.should == [@first, @last]
    end
  end
end

This test is okay. It tests if the named scope does what it needs to do. And there’s also the problem. Scopes are part of ActiveRecord and are already extensively tested there. All we need to do is check if we configure the scope correctly.

What we need is a way to inspect what where and order rules are set for a particular scope and make sure those are the correct ones. We can then trust ActiveRecord to keep its promise to execute the proper SQL query for us.

Here’s another test that utilizes some Rails 3 methods you may not have heard of before.

describe Post do
  context 'scopes' do
    it "should only return published posts" do
      Post.published.where_values_hash.should == {:published => true}
    end

    it "should return posts in the correct order" do
      Post.latest.order_values.should == ["created_at DESC"]
    end
  end
end

The where_values_hash and order_values allow you to inspect what a scopes doing. By writing your test this way you achieve two import goals:

  1. You test your code (instead of the ActiveRecord)
  2. You don’t use the database, which is a significant speed boost

Happy testing to you all!

Related

RSpec speed-up (24.6%) by tweaking ruby garbage collection
·237 words·2 mins
Ruby Rails Rspec Speed Garbage Collection GC
Rails 3 + Devise + Uploadify = No Flash Session Hacks
·550 words·3 mins
Rails Rails3 Devise Uploadify Flash
Once and for all: Rails migrations integer :limit option
·99 words·1 min
MySQL Ruby on Rails Rails Sql Migrations Integer Limit