如何在rails

时间:2017-08-15 03:48:50

标签: ruby-on-rails rspec rspec-rails

我有以下情况:

EDITED

在我的routes.rb

namespace :api, defaults: { format: :json } do
    namespace :v1 do
        # the definitions of other routes of my api
        # ...
        match '*path', to: 'unmatch_route#not_found', via: :all
    end
end

EDITED

我的控制器:

class Api::V1::UnmatchRouteController < Api::V1::ApiController
  def not_found
    respond_to do |format|
      format.json { render json: { error: 'not_found' }, status: 404 }
    end
  end
end

我的测试如下所示:

require 'rails_helper'

RSpec.describe Api::V1::UnmatchRouteController, type: :controller do
  describe 'get response from unmatched route' do
    before do
      get :not_found, format: :json
    end

    it 'responds with 404 status' do
      expect(response.status).to eq(404)
    end

    it 'check the json response' do
      expect(response.body).to eq('{"error": "not_found"}')
    end
  end
end

对我来说似乎是正确的,但是我对it1) Api::V1::UnmatchRouteController get response from unmatched route responds with 404 status Failure/Error: get :not_found, format: :json ActionController::UrlGenerationError: No route matches {:action=>"not_found", :controller=>"api/v1/unmatch_route", :format=>:json} # /home/hohenheim/.rvm/gems/ruby-2.3.1@dpms-kaefer/gems/gon-6.1.0/lib/gon/spec_helpers.rb:15:in `process' # ./spec/controllers/api/v1/unmatch_route_controller_spec.rb:14:in `block (3 levels) in <top (required)>' 个版本都有同样的错误:

/api/v1/foo

EDITED

当我的api中没有其他路径可用时,使用自定义 json 404响应触发此路由的目的。当我们访问以下路线时,此路线和控制器正在按预期工作:/api/v1/barPOST /7fa070bc-4e98-4bd1-b525-d5564b918e4c

如何正确编写测试?

其他信息:Rails 4.2.6,Rspec 3.5.4

3 个答案:

答案 0 :(得分:1)

看一下这个链接:

https://apidock.com/rails/ActionDispatch/Routing/Mapper/Base/match

它说:

  

请注意:controller,:action和:id被解释为url查询参数,因此可以通过动作中的params获得。

     

匹配&#34;:controller /:action /:id&#34;

您的路线是:

match '*path', to: 'unmatch_route#not_found', via: :all

所以你的测试试图找到一条路线:action =&gt;&#34; not_found&#34; inside:controller =&gt;&#34; api / v1 / unmatch_route&#34;。但是你的routes.rb没有这条路线。

尝试这样的事情:

match 'unmatch_route/not_found', to: 'unmatch_route#not_found', via: :all

如果你真的需要使用* path试试这个:

match '/:path/', :to => 'unmatch_route#not_found', :path=> /.*/, :as =>'not_found'

答案 1 :(得分:1)

如果您尝试编写路线规范,它也不会起作用,它会返回一些奇怪的东西。

 Failure/Error:
       expect(get("/unmatch")).
         to route_to("unmatch_route#not_found")
   The recognized options <{"controller"=>"unmatch_route", "action"=>"not_found", "path"=>"unmatch"}> did not match <{"controller"=>"unmatch_route", "action"=>"not_found"}>, difference:.
   --- expected
   +++ actual
   @@ -1 +1 @@
   -{"controller"=>"unmatch_route", "action"=>"not_found"}
   +{"controller"=>"unmatch_route", "action"=>"not_found", "path"=>"unmatch"}

除了动作not_found之外,它返回了path =&gt;无法控制的原因可能是控制器规格无法按预期工作的原因。因此,您可以使用下面的请求测试代替控制器测试。

require 'rails_helper'

RSpec.describe "get response from unmatched route", :type => :request do
  before do
    get '/not_found', format: :json
  end

  it 'responds with 404 status' do
    expect(response.status).to eq(404)
  end

  it 'check the json response' do
    expect(response.body).to eq('{"error": "not_found"}')
  end
end

答案 2 :(得分:0)

我还发现自己想要测试API错误的响应是呈现JSON,而不是编写简单挽救ActionController::RoutingError的规范。

以下request spec使用Rails 6.0和RSpec 3.9为我工作:

require 'rails_helper'

RSpec.describe '404 response for API endpoints' do
  it 'renders an error in JSON' do
    render_exceptions do
      get '/api/v1/fictional-endpoint', headers: { 'Accept' => 'application/json' }
    end

    expect(response).to have_http_status(:not_found)
    expect(response['Content-Type']).to include('application/json')
    expect(json_response.fetch(:errors)).to include('Not found')
  end

  private

  def json_response
    JSON.parse(response.body, symbolize_names: true)
  end

  def render_exceptions
    env_config = Rails.application.env_config
    original_show_exceptions = env_config['action_dispatch.show_exceptions']
    original_show_detailed_exceptions = env_config['action_dispatch.show_detailed_exceptions']
    env_config['action_dispatch.show_exceptions'] = true
    env_config['action_dispatch.show_detailed_exceptions'] = false
    yield
  ensure
    env_config['action_dispatch.show_exceptions'] = original_show_exceptions
    env_config['action_dispatch.show_detailed_exceptions'] = original_show_detailed_exceptions
  end
end

参考: