How to test controller actions with complicated queries?
Supposing I have the following action:
def index
@posts = Post.joins(:tags).where(:tags => {:id => params[:tag_id]})
end
It exposes @posts
to the view, which will display every post with the given tag.
Everything works fine, but I'm stuck trying to figure out the best way to test it.
I don't really like mocking, since it could brake the test if I changed that line to:
@posts = Post.where(:tags => {:id => params[:tag_id]}).joins(:tags)
I don't really want to hit the database, as it'd reduce the test speed, but I'm considering extracting the query to a method inside the model, and test it there if it's the only way to do it.
EDIT: Yes, I know I could use Tag.find(params[:tag_id])
in this case, but this is not what the question is about. I just didn't want to introduce another model in th开发者_如何学Goe query and make it harder to explain deviating the focus from the real problem, which is: Should we keep complex queries in the controller? If so, what's the best way to test it?
This is what i like to do. Generally, i like to integrate database testing inside my tests( though some would disagree, i personally like it ). I would create like 3 factories(:post) and maybe some tags as dummy data and then i would call on the controller and check whether the received @posts is what i would expect.
So, according to the comments extracting to the model is the best thing to do. That's how I did it:
post.rb:
class Post
scope :tagged_as, lambda {|tag_id| where(:tag_id => tag_id)}
end
posts.yml:
one:
title: Post 1
tags: one, three
two:
title: Post 2
tags: two, three
post_test.rb:
test 'find by tag' do
posts = Post.tagged_as(tags(:one))
assert_includes posts, posts(:one)
refute_includes posts, posts(:two)
end
精彩评论