I've run into this problem with testing. Let's assume I have two models, User and Post, where user has_many :posts.
I'm trying to spec out a code block that includes something like this:
user = User.find(123)
post = user.posts.find(456)
I know how to mock out the User.find
and user.posts
parts. The user.posts
mock returns an array of Post objects. And when it get's to .find(456)
part, everything breaks down with no block given
exception.
So my question here is: what do I return as the result of the user.posts
mock, so that .find(456)
method works on it? User.first.posts.class
says it's Array, but obviously there's something more that makes the AR-style find calls work. I'm not overjoyed by the prospect of mocking out find method on the returned object.
PS Before you suggest the obvious and good answer of stop mocking about and using fixtures/seeding the test database with necessary data, here's the catch: legacy scheme. Both User and Post work on top of database views not tables, and changing it so that they are tables in test database seems wrong to me.
The issue is that user.posts
isn't actually a simple Array
; it's an association proxy object. The way to stub it is probably something like this (though the exact syntax depends on which mocking framework you're using):
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
Then in your test, User.find(123)
will return @user
and @user.posts.find(456)
will return @post
. If you need @user.posts
to act like more of the Array
in your tests you can create a mock(Array)
and stub the [](index)
method.
You could look into the stub_chain method offered by RSpec.
http://apidock.com/rspec/Spec/Mocks/Methods/stub_chain#855-stub-chain-is-very-useful-when-testing-controller-code
Update: Per ryan2johnson9 the updated documentation is : https://relishapp.com/rspec/rspec-mocks/v/3-2/docs/working-with-legacy-code/message-chains
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With