问题
Let's say I have a page which lists articles. The code in the controller used to be
# articles#index
@articles = Article.paginate(page: params[:page], per_page: 10, order: :title)
and my test was like
# 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
Ok fine. Now my code changes a bunch. The index is like
@articles = Article.find(:all, conditions: complicated_status_conditions)
.sort_by { |a| complicated_weighted_rating_stuff }
.select { |a| complicated_filters }
.paginate(...)
Or something. So what should my request spec now look like? I don't want to just copy and paste the application code into the test, but at the same time, the conditions and ordering are now fairly complex, so testing the existence and order of all the expected elements will definitely fail unless I emulate the index controller.
What's the best way to do this, avoid testing so specifically, copy in the application code? Refactor the query to some central place like a model and re-use it in the tests?
回答1:
# articles#index
@articles = Article.paginate(page: params[:page], per_page: 10, order: :title)
The way we test this is not by writing Article.paginate(page: params[:page], per_page: 10, order: :title)
again in the spec. The spec must test the result of your program code, not copying over your program code itself!
Long story short - you must just call articles#index
controller, and afterwards just check the @articles
variable. i.e.
# 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
This way, you directly test using the @articles
variable itself, without having to do a second query (which both consumes unnecessary time, as well as results in copying over code).
If you want to test the actual query itself, then since your query is complicated, you should write a spec like the following:
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]
Edit: Footnote Edit 2: Added extra example for testing the actual query
来源:https://stackoverflow.com/questions/16999087/how-to-write-integration-test-for-complicated-rails-index-best-practices