假设我有一个列出文章的页面。控制器中的代码曾经是
# articles#index
@articles = Article.paginate(page: params[:page], per_page: 10, order: :title)
我的测试就像
# spec/requests/article_pages_spec
Article.paginate(page: 1, per_page:10, order: :title).each do |a|
a.should have_selector('h3', text: a.title)
end
好的。现在我的代码改变了一堆。索引就像
@articles = Article.find(:all, conditions: complicated_status_conditions)
.sort_by { |a| complicated_weighted_rating_stuff }
.select { |a| complicated_filters }
.paginate(...)
或者其他什么。那么我的请求规范现在应该是什么样的呢?我不想只是将应用程序代码复制并粘贴到测试中,但同时,条件和顺序现在相当复杂,因此测试所有预期元素的存在和顺序肯定会失败,除非我模仿索引控制器。
最好的方法是什么,避免如此具体地进行测试,复制应用程序代码?将查询重构为某个中心位置(如模型)并在测试中重复使用它?
答案 0 :(得分:3)
# articles#index
@articles = Article.paginate(page: params[:page], per_page: 10, order: :title)
我们通过在规范中再次编写Article.paginate(page: params[:page], per_page: 10, order: :title)
来测试它的方式是而不是。规范必须测试程序代码的结果,而不是复制程序代码本身!
长话短说 - 您必须只需拨打articles#index
控制器,然后只需检查@articles
变量即可。即。
# We usually call this as a controller spec
# spec/controllers/articles_controller
# But feel free to put it anywhere you want
describe ArticlesController do
it "should ..." do
get :index
# assigns[:articles] will give the @articles variable contents
assigns[:articles].each do |a|
response.should have_selector('h3', text: a.title)
end
end
end
这样,您可以直接使用@articles
变量本身进行测试,而无需进行第二次查询(这会消耗不必要的时间,并导致复制代码)。
如果您想测试实际的查询本身,那么由于您的查询很复杂,您应该编写如下的规范:
it "should ..." do
# Create 10 articles in the database
# out of which only 5 are expected to match the expected output
article1 = Article.create! ...
...
article10 = Article.create! ...
get :index
# Test whether the articles are correctly filtered and ordered
assigns[:articles].should == [article5, article3, article7, article1, article4]
编辑:脚注 编辑2:添加了测试实际查询的额外示例