Rails: Testing named scopes with RSpec

Viewed 37601

I am new to testing Rails web applications and RSpec. I work with legacy code and need to add tests. So what is the best way to test finders and named scopes with RSpec?

I find in Google a few approaches but they are not ideal. For example:

http://paulsturgess.co.uk/articles/show/93-using-rspec-to-test-a-named_scope-in-ruby-on-rails

it "excludes users that are not active" do
    @user = Factory(:user, :active => false)
    User.active.should_not include(@user)
end

or

http://h1labs.com/notebook/2008/8/21/testing-named-scope-with-rspec

it "should have a published named scope that returns ..." do
  Post.published.proxy_options.should == {:conditions => {:published => true}}
end

I find best approach (IMHO) in "Rail Test Prescriptions":

should_match_find_method :active_only { :active == true }

where should_match_find_method custom helper method

4 Answers

David Chelimsky testing scopes (updated)

David Chelimsky example, (linked by Sam Peacey's comment), modernised.

# app/models/user.rb

class User < ActiveRecord::Base
  scope :admins, -> { where(admin: true) }
end
# spec/models/user_spec.rb

RSpec.describe User, type: :model do
  describe ".admins" do
    it "includes users with admin flag" do
      admin = User.create!(admin: true)
      expect(User.admins).to include(admin)
    end

    it "excludes users without admin flag" do
      non_admin = User.create(admin: false)
      expect(User.admins).not_to include(non_admin)
    end
  end
end

This produces a more 'spec-like' output (when using --format documentation):

User
  .admins
    includes users with admin flag
    excludes users without admin flag

Note about origination of this answer:

David Chelimsky, the RSpec lead at the time, answered this question and Sam Peacey's link to it has more votes than the actual answer. The answer is not easy to find and follow as he is replying to someone and editing their answer in an email chain. This answer cleans that up and updates the RSpec code as, I guess, he would have written it today.

Related