Выполнение цепочечных запросов в Rails 3 и Rspec

Я пытаюсь проверить область видимости, которая основана на цепочке других областей. ( "public_stream" ниже).

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) }

Используя такой тест:

    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

Однако я продолжаю получать эту ошибку:

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

Кажется, includes_values ​​является переменной экземпляра объекта ActiveRecord:: Relation, но когда я пытаюсь его заглушить, я все равно получаю ту же ошибку. Мне было интересно, есть ли у кого-нибудь опыт в создании новых запросов Rails 3? Я могу найти кучу обсуждения над 2.x find hash, но ничего о том, как проверить, что такое текущее.

Ответы

Ответ 1

Я использую для этого rspec stub_chain. Вы могли бы использовать что-то вроде:

some_model.rb

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

Контроллер

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

спецификации

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

Ответ 3

Во-первых, вы, вероятно, не должны тестировать встроенную функцию Rails.

Вы должны писать только модульные тесты для кода, который вы написали сами (что должно быть второсортным, если вы практикуете TDD). Rails поставляется со своим полным набором модульных тестов для своей встроенной функциональности - нет смысла в копировании этого.

Что касается ошибки, я думаю, что ваша проблема в этой строке:

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

Вы ожидаете, что цепочка вернет Factory, что фактически станет экземпляром ActiveRecord, но на самом деле каждое отношение возвращает еще один ActiveRecord::Relation.

Таким образом, ваше ожидание само по себе является неправильным и может действительно вызывать возникшую ошибку.

Имейте в виду, что области не возвращают ожидаемые записи, пока вы явно не перейдете через них. Кроме того, записи отношений никогда не вернут одну запись. Они всегда будут либо возвращать пустой массив, либо массив с записями.

Ответ 4

Попробуйте перейти на Arel, так как это может быть так, что область видимости отсутствует.

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