Skip to content
Richard Lewis edited this page Jan 7, 2014 · 3 revisions

Here are some Matchers for Rspec tests

obj.should be_true, obj.should be_false, obj.should be_nil, obj.should be_empty – the first three of these could be done by == true, etc. be_empty will be true if obj.empty? is true.

obj.should exist – does this object even exist yet?

obj.should have_at_most(n).items, object.should have_at_least(n).items – like have, but will pass if there are more or fewer than n items, respectively.

obj.should include(a[,b,...]) – are one or more items in an array?

obj.should match(string_or_regex) – does the object match the string or regex?

obj.should raise_exception(error) – does this method raise an error when called?

obj.should respond_to(method_name) – does this object have this method? Can take more than one method name, in either strings or symbols.

RSpec-Rails

Models

obj.should be_valid
obj.should have(n).errors_on(:field)
obj.errors.on(:field).should == "is required"

General

response.should be_valid
response.should_not be_valid

response.should be_success
response.should be_redirect

response.should redirect_to("path/to/action")
response.should redirect_to("http://test.host/path/to/action")
response.should redirect_to(:action => 'list')

response.should render_template('list')
response.should render_template('same_controller/list')
response.should render_template('other_controller/list')

# partials
response.should render_template('_a_partial')
response.should render_template('same_controller/_a_partial')
response.should render_template('other_controller/_a_partial')

Routing

"path".should route_to(expected) # assumes GET
{ :get => "path" }.should route_to(expected)
{ :put => "path" }.should route_to(expected)

{ "path" }.should_not be_routable # assumes GET
{ :get => "path" }.should_not be_routable
{ :put => "path" }.should_not be_routable

Content

response.should have_tag("div", "some text")
person_address_tag.should have_tag("input#person_address") # in a helper

response.should have_tag("div#form") do
  with_tag("input#person_name[name=?]", "person[name]")
end

response.should have_tag("div#1") do
  without_tag("span", "some text that shouldn't be there")
end

response.should include_text("This text will be in the actual string")

Mail

response.should send_email(*args, &block)

ActiveModel Matchers

Matchers to test validations and mass assignments:

describe Post do
  it { should validate_uniqueness_of(:title) }
  it { should validate_presence_of(:body).with_message(/wtf/) }
  it { should validate_presence_of(:title) }
  it { should validate_numericality_of(:user_id) }
  it { should validate_numericality_of(:user_id).only_integer }
  it { should validate_acceptance_of(:eula) }

  it { should validate_format_of(:name).
                  with('12345').
                  with_message(/is not optional/) }
  it { should validate_format_of(:name).
                not_with('12D45').
                with_message(/is not optional/) }
  it { should validate_numericality_of(:age) }
  it { should validate_confirmation_of(:password) }


  # validates_uniqueness_of requires an entry to be in the database already
  it "validates uniqueness of title" do
    Post.create!(title: "My Awesome Post", body: "whatever")
    should validate_uniqueness_of(:title)
  end
end

describe User do
  it { should_not allow_value("blah").for(:email) }
  it { should allow_value("[email protected]").for(:email) }
  it { should ensure_inclusion_of(:age).in_range(1..100) }
  it { should ensure_exclusion_of(:age).in_range(30..60) }
  it { should_not allow_mass_assignment_of(:password) }
end

it { should ensure_length_of(:password).
              is_at_least(6).
              is_at_most(20) }
it { should ensure_length_of(:name).
              is_at_least(3).
              with_short_message(/not long enough/) }
it { should ensure_length_of(:ssn).
              is_equal_to(9).
              with_message(/is invalid/) }

ActionController Matchers

Matchers to test common patterns:

describe PostsController, "#show" do
  context "for a fictional user" do
    before do
      get :show, :id => 1
    end

    it { should assign_to(:user) }
    it { should respond_with(:success) }
    it { should render_template(:show) }
    it { should_not set_the_flash }
    it { should set_the_flash[:alert].to("Password doesn't match") }
  end
end

# other examples
it { should assign_to(:user) }
it { should_not assign_to(:user) }
it { should assign_to(:user).with_kind_of(User) }
it { should assign_to(:user).with(@user) }

it { should render_with_layout }
it { should render_with_layout(:special) }
it { should_not render_with_layout }

it { should respond_with(:success)  }
it { should respond_with(:redirect) }
it { should respond_with(:missing)  }
it { should respond_with(:error)    }
it { should respond_with(501)       }

it { should respond_with_content_type(:xml)  }
it { should respond_with_content_type(:csv)  }
it { should respond_with_content_type(:atom) }
it { should respond_with_content_type(:yaml) }
it { should respond_with_content_type(:text) }
it { should respond_with_content_type('application/rss+xml') }
it { should respond_with_content_type(/json/) }

it { should set_session(:message) }
it { should set_session(:user_id).to(@user.id) }
it { should_not set_session(:user_id) }

it { should set_the_flash }
it { should set_the_flash.to("Thank you for placing this order.") }
it { should set_the_flash.to(/created/i) }
it { should set_the_flash.to(/logged in/i).now }
it { should_not set_the_flash }

it { should filter_param(:password) }

ActionMailer Matchers

it { should have_sent_email.with_subject(/is spam$/) }
it { should have_sent_email.from('[email protected]') }
it { should have_sent_email.with_body(/is spam\./) }
it { should have_sent_email.to('[email protected]') }
it { should have_sent_email.with_part('text/html', /HTML spam/) }
it { should have_sent_email.with_subject(/spam/).
                            from('[email protected]').
                            with_body(/spam/).
                            to('[email protected]') }

it {should have_sent_email.to {@user.email} }
it { should have_sent_email.reply_to([user, other]) }