简体   繁体   中英

Rspec 3 Rails 4 mock chained method call with parameters

I am attempting to mock the following line:

publishers = AdminUser.where(can_publish: true).pluck(:email)

I have tried:

relation = instance_double('AdminUser::ActiveRecord_Relation')
allow(AdminUser).to receive(:where).with(can_publish: true).and_return(relation)
allow(relation).to receive(:pluck).with(:email).and_return(['email', 'email2'])

Unfortunately the expectation doesn't seem to match. No errors are thrown, but the methods aren't mocked .

I have also tried just and let pluck work.

  allow(AdminUser).to receive(:where).with(can_publish: true).and_return([object, object2])

However, this expectation is too generate and fails when it where matches another where call higher in the code.

How can I mock this line?

Although you can use receive_message_chain as suggested, treat the need for such complexity as an indication that your class's interface could be cleaner.

The RSpec docs say to consider any use of receive_message_chain a code smell .

A better approach would be to define a class method on AdminUser named something like publisher_emails , which which will be much simpler to stub, and also improves the readability of your code.

You can stub method calls on doubles:

require 'rails_helper'

RSpec.describe AdminUser, type: :model do
  let(:expected) { ["a@example.com"] }
  let(:relation) { double(pluck: expected) }

  it "returns the expected value" do
    allow(AdminUser).to receive(:where).with(can_publish: true).and_return(relation)
    publishers = AdminUser.where(can_publish: true).pluck(:email)
    expect(publishers).to eq expected
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM