2010-01-29 3 views
11

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

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

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

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

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

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

ответ

16

Вопрос заключается в том, что user.posts не является Фактически a 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).

+1

Это «некрасиво» так, что я не хотел делать, но ваше упоминание о «ассоциации прокси-объект» предоставил мне ключевые слова, которые я отсутствовал, и поиск его привел к тому, что я искал, спасибо! –

+7

@Toms, Если ваше решение уникально среди этих ответов, возможно, вы могли бы добавить добавить его в качестве другого ответа. Я хотел бы посмотреть, как вы это решили. –

+0

Уродливый путь, издевается над насмешками. Я был просто счастлив понять это - я не первый раз сталкивался с этой ситуацией, и это беспокоило меня. –

7

Вы можете изучить метод stub_chain, предлагаемый RSpec.

http://apidock.com/rspec/Spec/Mocks/Methods/stub_chain#855-stub-chain-is-very-useful-when-testing-controller-code

Update: Per ryan2johnson9 обновленная документация: https://relishapp.com/rspec/rspec-mocks/v/3-2/docs/working-with-legacy-code/message-chains

+1

для rspec 3.2 [receive_message_chain] (https://relishapp.com/rspec/rspec-mocks/v/3-2/docs/working-with-legacy-code/message-chains) – ryan2johnson9

Смежные вопросы