Отказывание отношения поведения ActiveRecord в тестах RSpec

Я столкнулся с этой проблемой при тестировании. Предположим, у меня две модели: User и Post, где пользователь has_many: posts.

Я пытаюсь описать блок кода, который включает в себя что-то вроде этого:

user = User.find(123)
post = user.posts.find(456)

Я знаю, как издеваться над частями User.find и user.posts. user.posts mock возвращает массив объектов Post. И когда он доходит до части .find(456), все ломается с исключением no block given.

Итак, мой вопрос: что я возвращаю в результате user.posts mock, так что метод .find(456) работает на нем? User.first.posts.class говорит, что это Array, но, очевидно, есть что-то большее, что заставляет работать называть AR-стиль. Меня не радует перспектива издеваться над методом find на возвращаемом объекте.

PS Прежде чем предлагать очевидный и хороший ответ о том, чтобы перестать насмехаться и использовать инвентарь/посев тестовой базы данных с необходимыми данными, вот схема уловки: устаревшая. Как пользователь, так и почта работают над представлениями базы данных без таблиц и меняют их так, чтобы они были таблицами в тестовой базе данных, мне кажется неправильным.

Ответ 1

Проблема в том, что user.posts на самом деле не простой Array; это объект прокси-объекта ассоциации. Способ заглушить это, вероятно, что-то вроде этого (хотя точный синтаксис зависит от того, какую издевательскую структуру вы используете):

def setup
  @user = mock(User)
  User.stub(:find).with(123).return(@user)
  user_posts = mock(Object)
  @user.stub(:posts).return(user_posts)
  @post = mock(Post)
  user_posts.stub(:find).with(456).return(@post)
end

Затем в вашем тесте User.find(123) вернется @user и @user.posts.find(456) вернет @post. Если вам нужно @user.posts действовать как больше Array в ваших тестах, вы можете создать mock(Array) и заглушить метод [](index).