Ruby on rails 如何使用复杂的查询测试控制器操作?

Ruby on rails 如何使用复杂的查询测试控制器操作?,ruby-on-rails,ruby,testing,controller,functional-testing,Ruby On Rails,Ruby,Testing,Controller,Functional Testing,假设我有以下动作: def index @posts = Post.joins(:tags).where(:tags => {:id => params[:tag_id]}) end 它向视图公开@posts,视图将显示带有给定标记的每篇文章 一切正常,但我一直在努力找出最好的测试方法 我真的不喜欢嘲弄,因为如果我把那句话改成: @posts = Post.where(:tags => {:id => params[:tag_id]}).joins(:tags)

假设我有以下动作:

def index
  @posts = Post.joins(:tags).where(:tags => {:id => params[:tag_id]})
end
它向视图公开
@posts
,视图将显示带有给定标记的每篇文章

一切正常,但我一直在努力找出最好的测试方法

我真的不喜欢嘲弄,因为如果我把那句话改成:

@posts = Post.where(:tags => {:id => params[:tag_id]}).joins(:tags)
我真的不想访问数据库,因为这会降低测试速度,但我正在考虑将查询提取到模型内的一个方法,并在那里测试它,如果这是唯一的方法


编辑:是的,我知道在这种情况下我可以使用
Tag.find(params[:Tag\u id])
,但这不是问题所在。我只是不想在查询中引入另一个模型,让解释焦点偏离实际问题变得更加困难,这就是:我们应该在控制器中保留复杂的查询吗?如果是这样,最好的测试方法是什么?

这就是我喜欢做的。通常,我喜欢在测试中集成数据库测试(尽管有些人不同意,但我个人喜欢)。我会创建3个工厂(:post)和一些标签作为虚拟数据,然后我会调用控制器,检查收到的@posts是否符合我的预期。

因此,根据注释提取到模型是最好的做法。我就是这样做的:

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

一个附带问题,为什么不:@posts=Tag.find(params[:Tag_id]).posts。它感觉更自然,而且没有什么需要测试的。复杂的查询应该是模型中的作用域,而不是控制器中的作用域。@tokland这只是一个带有
连接
其中
的查询示例,而不是真正的代码。我只是想让它变得简单,这样就可以很容易地解释它的作用。你应该把所有复杂的业务逻辑从控制器中移出,放到模型中。所以这个问题真的变成了:我如何在模型中测试它?你到底为什么要重新创建关联而不是做
标记.posts
?更不用说你要求一个标记id,但提供一个标记对象。你可以做tag.find(tag_id).posts。@Rein在评论中看到我给tokland的答案。这不是真正的代码。我只是试着做一个简单的查询,这样每个人都会关注控制器与复杂查询的测试问题。不幸的是,我认为结果正好相反,所以我要编辑这个问题。