Stubbing Chained Queries in Rails 3 and Rspec

I'm trying to test a scope I have that is based upon a chain of other scopes. ("public_stream" below).

scope :public, where("entries.privacy = 'public'")
scope :completed, where("entries.observation <> '' AND entries.application <> ''")
scope :without_user, lambda { |user| where("entries.user_id <> ?", user.id) }
scope :public_stream, lambda { |user| public.completed.without_user(user).limit(15) }

Using a test like this:

    it "should use the public, without_user, completed, and limit scopes" do
      @chain = mock(ActiveRecord::Relation)
      Entry.should_receive(:public).and_return(@chain)
      @chain.should_receive(:without_user).with(@user).and_return(@chain)
      @chain.should_receive(:completed).and_return(@chain)
      @chain.should_receive(:limit).with(15).and_return(Factory(:entry))

      Entry.public_stream(@user)
    end

However, I continue to receive this error:

Failure/Error: Entry.public_stream(@user)
undefined method `includes_values' for #<Entry:0xd7b7c0>

It seems includes_values is an instance variable of the ActiveRecord::Relation object, but when I try to stub it, I still receive the same error. I was wondering if anyone had experience with stubing Rails 3's new chained queries? I can find a bunch of discussion over 2.x's find hash, but nothing on how to test what's current.

Answers


I use rspec's stub_chain for this. You might be able to use something like:

some_model.rb

scope :uninteresting, :conditions => ["category = 'bad'"],
                      :order => "created_at DESC"

Controller

@some_models = SomeModel.uninteresting.where(:something_else => true)

spec

SomeModel.stub_chain(:uninteresting, :where) {mock_some_model}

Same Answer as above.

SomeModel.stub_chain(:uninteresting, :where) {mock_some_model}

Rspec 3 version:

allow(SomeModel).to receive_message_chain(:uninteresting).and_return(SomeModel.where(nil))

Reference:

https://relishapp.com/rspec/rspec-mocks/docs/method-stubs/stub-a-chain-of-methods


First off, you probably should not be testing built-in Rails functionality.

You should only be writing unit tests for code that you have written yourself (which should be second-nature if you practice TDD) – Rails ships with its own comprehensive suite of unit tests for its built-functionality – there is no point in replicating this.

As far as the error being thrown, I think that your issue is on this line:

@chain.should_receive(:limit).with(15).and_return(Factory(:entry))

You are expecting the chain to return a Factory, which would effectively be an instance of ActiveRecord, but in actuality every relation returns yet another ActiveRecord::Relation.

Thus, your expectation itself is incorrect, and may indeed be causing the error that's being thrown.

Keep in mind, that scopes don't actually return the records you expect, until you explicitly iterate over them. Also, the relation's records will never return a single record. They will always either return an empty array or an array with records.


Try passing on the Arel, as it might be the case that it scopes are going missing.

it "should use the public, without_user, completed, and limit scopes" do
  @chain = Entry
  @chain.should_receive(:public).and_return(@chain.public)
  @chain.should_receive(:without_user).with(@user).and_return(@chain.without_user(@user))
  @chain.should_receive(:completed).and_return(@chain.completed)
  @chain.should_receive(:limit).with(15).and_return(Factory(:entry))

  Entry.public_stream(@user)
end

Need Your Help

Creating a CSS3 box-shadow on all sides but one

html css css3 shadow

I've got a tabbed navigation bar where I'd like the open tab to have a shadow to set it apart from the other tabs. I'd also like the whole tab section to have a single shadow (see bottom horizontal...

Massively refactor - how to add final keyword to Java method argument

java intellij-idea refactoring checkstyle

This might be a simple question: How can I massively refactor my Java code to make most of the method argument as "final"? This is to follow one of our "checkstyle" rule. We have thousands of Java ...