This project is archived and is in readonly mode.

#5977 ✓invalid
Fernando Guillen

Functional tests don't care about http-verb that you use on the simulate request.

Reported by Fernando Guillen | November 15th, 2010 @ 03:09 PM

Context:

Rails: 3.0.1
Ruby: 1.8.7

In case I have these routes:

resources :my_things do
  collection do 
    get :my_get_action
    post :my_post_action
  end
end

I can simulate this request in my functional test without any warning:

# my_things_controller_test.rb
post(:my_get_action)
get(:my_post_action)

What it looks like is that it doesn't matter which request type do you use.

See this very simple Rails project that reproduce this behavior in its functional tests:

These are the tests I'm trying:

require 'test_helper'

class MyThingsControllerTest < ActionController::TestCase
  test "should respond to the get action" do
    get(:my_get_action)

    assert_response :success
    assert_equal("my get action", @response.body)
  end

  test "should respond to the post action" do
    post(:my_post_action)

    assert_response :success
    assert_equal("my post action", @response.body)
  end

  test "should respond to the get action with post verb" do
    assert_raise(ActionController::RoutingError) do
      post(:my_get_action)
    end
  end

  test "should not respond to the post action with get verb" do
    assert_raise(ActionController::RoutingError) do
      get(:my_post_action)
    end
  end
end

This is the result:

$ rake test:functionals
(in /Users/fguillen/Develop/Rails/Contribute/TestingRoutesVerb)
Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
F.F.
Finished in 0.180686 seconds.

  1) Failure:
test_should_not_respond_to_the_post_action_with_get_verb(MyThingsControllerTest) [/test/functional/my_things_controller_test.rb:25]:
<ActionController::RoutingError> exception expected but none was thrown.

  2) Failure:
test_should_respond_to_the_get_action_with_post_verb(MyThingsControllerTest) [/test/functional/my_things_controller_test.rb:19]:
<ActionController::RoutingError> exception expected but none was thrown.

4 tests, 6 assertions, 2 failures, 0 errors
rake aborted!
Command failed with status (1): [/System/Library/Frameworks/Ruby.framework/...]

Comments and changes to this ticket

  • Andrew White

    Andrew White November 17th, 2010 @ 05:49 PM

    • State changed from “new” to “invalid”
    • Importance changed from “” to “Low”

    Functional tests call the controller action directly and don't go through the router. Use an ActionDispatch::IntegrationTest to check the routing constraints. e.g:

      rails generate test_unit:integration my_controller_routing
    
  • Fernando Guillen

    Fernando Guillen November 17th, 2010 @ 08:09 PM

    But then what is the propose of having the five verbs in the ActionController::TestCase if I can use any of them without any restriction or diference?

    It is not intuitive.

    And besides the ActionController::TestCase, some way, looks to the defined routes because if don't have the route defined on your routes.rb it raises an ActionController::RoutingError.

  • Andrew White

    Andrew White November 18th, 2010 @ 07:05 AM

    The get, post, etc. methods are just wrappers around the process method of ActionController::TestCase. All they do is set the REQUEST_METHOD header in the Rack environment so that any code in your controller that is dependent on the request method acts appropriately, e.g.

      # routes.rb
      match '/basket', :to => 'shop#basket', :via => [:get, :post]
    
      # app/controllers/shop_controller.rb
      class ShopController < ApplicationController
        before_filter :load_basket
    
        def basket
          @basket.update(params[:basket]) if request.post?
        end
    
        protected
          def load_basket
            @basket = Basket.new(session[:basket])
          end
      end
    

    The routing error you get is because the process method builds a request uri so it's a generation error and not a recognition error (generation of urls ignores HTTP verbs as well).

    Functional tests are meant to be isolated tests of your controller - if you need to test the full stack use an integration test.

  • Fernando Guillen

    Fernando Guillen November 18th, 2010 @ 09:58 AM

    Ok, I understand pretty much better all this behavior.

    So the verbs in the ActionController::TestCase are just to mark this request with this REQUEST_METHOD header in order to be used (or not) in our Controller.

    And also I have realized that we are also checking that the url we are calling can be built based on our routes definition, but without taken care about the verbs restrictions. So it should be able to be generated but it doesn't need to be recognized.

    (This last point sounds a few inconsistent for me, but I understand I don't have the whole picture in my mind)

    Thanks for your explanation.

  • Andrew White

    Andrew White November 18th, 2010 @ 10:29 AM

    That's pretty much it except the route is being built so that the REQUEST_URI header can be set and not to check whether the route can be generated (though it obviously it needs to be).

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages