End-to-end Integration Tests for Rails REST APIs and ActiveResource Clients

HttpMock is great to test the client side of a REST API. But if you’re responsible for client and server side of the API, it makes sense to do full end-to-end tests from your application’s controllers to the client app. Up to now, you’d need to set up a local server to end-to-end-test the ActiveResource requests from the client app against.

Instead, I’d like to just use Rails’ integration test infrastructure. All ActiveResource requests can be directly routed to the app’s controller, just as known from integration tests. This is how tests could then look like:

  require 'active_resource_integration_test_support'
 
  class APIIntegrationTest < ActionController::IntegrationTest
    test "API requests work end-to-end" do
      ActiveResource::Connection.with_integration_test_session(open_session) do
        result = APIClient.some_method_that_requires_api_access
        assert result
      end
    end
  end

All you need to get there, is drop this monkey patch into your app’s lib directory and require it from the ActiveResource integration tests.

module ActiveResource
  class Connection
    # ActiveResource requests will use the supplied
    # ActionController::Integration::Session to execute its request in the
    # given block.
    #
    def self.with_integration_test_session (session)
      previous_session = Connection.integration_test_session
      begin
        Connection.integration_test_session = session
        yield
      ensure
        Connection.integration_test_session = previous_session
      end
    end
 
    private
    mattr_accessor :integration_test_session
 
    def request_with_integration_test_support (method, path, *arguments)
      if self.class.integration_test_session
        # arguments are data, header for post, put; else header
        header = arguments.last
        data = arguments.length > 1 ? arguments.first : nil
 
        Rails.logger.debug("#{method.to_s.upcase} #{path}")
        self.class.integration_test_session.send(method, path, data, header)
        #Rails.logger.debug(self.class.integration_test_session.response.body)
 
        handle_response(self.class.integration_test_session.response)
        self.class.integration_test_session.response
      else
        Rails.logger.debug("No session set, using default ActiveResource requests")
        request_without_integration_test_support(method, path, *arguments)
      end
    end
    alias_method_chain :request, :integration_test_support
  end
end

If you find this useful, have a look at the pending Rails patch at Lighthouse to support getting this into Rails.