Reputation: 928
I'm trying to run a unit testing on my API controllers in Rails. But it's not behaving like I thought it should.
This line works:
post '/api/sessions', params
This line however
post :create, params
will throw error
Failure/Error: post :create
URI::InvalidURIError:
bad URI(is not URI?): http://www.example.com:80create
I can use the first one, but would be good to know why doesn't the 2nd syntax works? Because I remember using that syntax in previous projects, and it works. I don't remember any special setup on my RSpec config.
Update: My codes
Api::ApiController
class Api::ApiController < ActionController::Base
include ApplicationHelper
end
Api::SessionsController
module Api
class SessionsController < Api::ApiController
def create
# find user and store in @user. I'm using jbuilder
render status: 201
end
end
end
RSpec
require 'rails_helper'
describe Api::SessionsController, :type => :controller do
describe '#POST' do
it 'should retrieve user' do
post '/api/sessions', params # this works
post :create, params # this fails
end
end
end
route.rb
Rails.application.routes.draw do
apipie
devise_for :users
root 'home#index'
namespace :api, defaults: { format: :json } do
resources :sessions, only: [:create]
resources :users, only: [:create]
resources :trips, only: [:create]
end
end
Based on the comment, I run raise method(:post).source_location.inspect
at the beginning of the test, and this is what I get.
For this project, which currently failed:
RuntimeError:
["/Users/tokwan/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/testing/integration.rb", 335]
And for other project, where post :create
works:
RuntimeError:
["/Users/tokwan/.rvm/gems/ruby-2.2.0/gems/actionpack-4.2.2/lib/action_controller/test_case.rb", 513]
Upvotes: 2
Views: 2279
Reputation: 84114
TLDR: It sounds like you thing you are running a controller spec, but actually you are running a request spec.
Rspec can find out the type of a spec through 2 mechanisms: If you tell it in the metadata for the example / example group,
describe "something", type: :controller do
..
end
or based on file location, if you have config.infer_spec_type_from_file_location!
in your spec helper. It looks like your spec is tagged as controller, but it sounds like something is overriding it: perhaps it's in the wrong location, or something else is changing its type.
As a recap, the differences between controller & requests specs:
These live in spec/controllers, with type: controller
. Rails calls these functional tests, but they are basically unit tests for individual controllers (especially with rspec, which by default skips the rendering of views).
Each spec tests a single invocation of a controller action. The invocation of the action doesn't use routing (although I think it is an error these days if there is no route mapped to the action). Rails provides helpers that will invoke the specified action with any desired parameters, e.g. get action: 'show', id: 1
. Rack Middlewares and so on are skipped.
These live in spec/requests
, spec/api
, and
spec/integration
. Rails calls them integration tests. These can span multiple requests and run through the entire middleware stack, render views etc. This isn't just a test of a single controller so you specify a path, rather than just an action, e.g. get '/articles/1'
Upvotes: 6