Rails: multiple receive requests in a single functional test

I would like to group some receive requests into the same tests, but I get erratic behavior. I have the following two tests:

test 'index for local seller (same site)' do seller = FactoryGirl.create :seller, business_site: @open_or.business_site get :index, nil, {user_id: seller.to_param } assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}" end test 'index for local seller (different site)' do seller = FactoryGirl.create :seller_local get :index, nil, {user_id: seller.to_param } assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}", false end 

which I would like to combine in one test, but if I do, the second statement will fail by mistake (exactly 0 elements were expected matching the "table # order_requests tr # order_request_1000244799", found 1). I really don't understand why? Something may not be reset correctly for the second get call. I searched for ways to "reset" the request without success.

Related: makes two requests to one controller in rails integration specifications

+4
source share
3 answers

One of the important differences that I noticed in functional tests (as opposed to integration) is that the state of the controller is not like reset between requests, which can lead to unexpected results. For example, consider this (contrived) controller:

 class ThingyController < ApplicationController def one @thingy = Thingy.first render :nothing => true end def two render :nothing => true end end 

The action 'one' sets @thingy, but the action 'two' does not. However, this functional test fails:

 test "thingy should not exist in second request" do get :one assert_not_nil assigns(:thingy), "thingy should exist in get_one" get :two assert_nil assigns(:thingy), "thingy should be absent in get_two" end 

Presumably, this is because @thingy from the first request remains as an instance variable in the controller throughout the entire test method.

Although you can make multiple calls to get / put / etc in one test, I think that they are not intended to test more than one action for each test method. In the Rails API TestCase docs :

Functional tests allow you to test one controller action per test method. This should not be confused with integration tests (see ActionDispatch :: IntegrationTest), which are more like “stories”, which may include several controllers and many actions (i.e. many different HTTP requests).

If you really want to combine the two actions, perhaps an integration test would be a better approach.

+8
source

Well, you don’t show the combined test, and you don’t show what the failure is, so it works pretty much in the dark, but to combine these tests I can do something like

 test 'index for seller (same site)' do first_seller = FactoryGirl.create :seller, business_site: @open_or.business_site get :index, nil, {user_id: first_seller.to_param } assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}" second_seller = FactoryGirl.create :seller_local get :index, nil, {user_id: second_seller.to_param } assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}", false end 

The above assumes that your individual tests pass, and if it is not, I can understand why this will not work (but I do not see very well in the dark)

By the way, tests do not fail by mistake, there is always a reason for a failed test, and usually it is a real failure or a poorly thought out test, since this is an error introduced by the programmer, and not a test error for all!

UPDATE - look in the browser to find out what is actually on the web page when the test fails using save_and_open_page, like railscast http://railscasts.com/episodes/275-how-i-test

The difference between combined tests and individual tests is that the database is cleared between each test, so your first seller will still exist in the database in your combined test, but will not exist in the second test when they are run as separate Tests

0
source

If you have many places where you distinguish between the behavior of the “same site” and “another site” (or any other two-level behavior), it may make sense to add a helper method to test_helper.rb, which simply adds two tests for you:

 def only_for_same_site_should(description, &action) class_eval do test "should #{description} if same site" do action.call(self, FactoryGirl.create :seller, true) end test "should NOT #{description} if different site" do action.call(self, FactoryGirl.create :seller_local, false) end end end 

And then use it in controller test classes as follows:

 only_for_same_site_should("have tag order_requests in index") do |test, seller, same_site| test.get :index, nil, {user_id: seller.to_param} assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}", same_site end 
0
source

All Articles