简体   繁体   English

如何用复杂的查询测试控制器动作?

[英]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. 它将@posts暴露给视图,该视图将显示具有给定标签的每个帖子。

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. 编辑:是的,我知道在这种情况下可以使用Tag.find(params[:tag_id]) ,但这不是问题所在。 I just didn't want to introduce another model in the 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. 我会创建3个factory(:post),也许还会创建一些标记作为虚拟数据,然后我将调用控制器并检查接收到的@posts是否符合我的期望。

So, according to the comments extracting to the model is the best thing to do. 因此,根据注释提取到模型是最好的方法。 That's how I did it: 我就是这样的:

post.rb: post.rb:

class Post
  scope :tagged_as, lambda {|tag_id| where(:tag_id => tag_id)}
end

posts.yml: posts.yml:

one:
  title: Post 1
  tags: one, three

two:
  title: Post 2
  tags: two, three

post_test.rb: 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM