How to use rspec-mocks

I. Introduction

  • What is rspec-mocks? It's a framework for rspec with helps to control the context in a code example by letting you set known return values, fake implementations of methods, and even set expectations that specific messages are received by an object.

II. Installation

  • Rspec-mocks is also integrate in rspec gem that be installed by this command:
gem install rspec
  • It can be installed separately by this command:
gem install rspec-mocks

III. Simple example

In this example, we need to write rspec for this method:

class UpdateUserAndSubject
  class << self
    dev perform user, subject
      ActiveRecord::Base.transaction do
        user.update_attributes! params[:user]
        subject.update_attributes! params[:subject]
      end
    rescue ActiveRecord::UnknownAttributeError, ActiveRecord::RecordInvalid
      false
    end
  end
end

It's easier to write rspec for case update successful. But how to write rspec for case rescue error? It's the reason why we need rspec-mocks.

1. Create fake object

We need to generate an active record error by this way:

let(:user){FactoryGirl.create :user}
let(:unknown_attribute_error){ActiveRecord::UnknownAttributeError.new "", ""}
let(:record_invalid){ActiveRecord::RecordInvalid.new user}

2. Fake object to test method by error case

Use allow(object).to receive(method){value} to fake object's method's value.

In this case, we need to fake object with error active record, so we can use allow(object).to receive(action).and_raise(error).

Finally, we have rspec for example method:

subject{UpdateUserAndSubject.perform user, subject}
it do
  allow(user).to receive(:update_attributes!).and_raise(unknown_attribute_error)
  is_expected.to eq false
end

it do
  allow(user).to receive(:update_attributes!).and_raise(record_invalid)
  is_expected.to eq false
end

IV. More about rspec-mocks

  • When need to fake more value for method, we use .and_return to do it. For example:
allow(user).to receive(:rank).and_return(1, 2, 3)
die.rank # => 1
die.rank # => 2
die.rank # => 3
die.rank # => 3
die.rank # => 3
  • When need to fake method with arguments, we use .with(*args) after receive(method).
  • When need to fake message validate, we use receive(:validate){"message"}.
  • We can fake class method easily:
allow(User).to receive(:find){user}

V. Conclusion

Rspec-mocks is very useful in rspec test. That's some simple case to use rspec-mocks in unit test. Hope that it's useful for someone. Thanks for reading!