首页 > 解决方案 > RSpec 错误 ActionController::UrlGenerationError: 测试控制器时

问题描述

我正在为我的 API 控制器编写规范(使用 RSpec)。当我测试索引的 GET 请求时一切正常,它返回预期的正文和成功的响应,但是,当我测试 show 操作的 GET 请求时,它会引发以下错误:

ActionController::UrlGenerationError:
   No route matches {:action=>"show", :controller=>"api/v1/contacts"}

这是我在规范文件中编写的代码:

require 'rails_helper'

RSpec.describe Api::V1::ContactsController do
  describe "GET #index" do
    context 'with a successful request'  do
      before do
        get :index
      end

      it "returns http success" do
        expect(response).to have_http_status(:success)
        expect(response.status).to eq(200)
      end

      it "JSON body response contains expected recipe attributes" do
        json_response = JSON.parse(response.body)
        expect(json_response.keys).to match_array(%w[data included])
      end
    end
    end

  describe "GET #show" do
    context 'with a successful request'  do
      before do
        get :show
      end

      it "returns http success" do
        expect(response).to have_http_status(:success)
        expect(response.status).to eq(200)
      end
    end
  end
end

这是命令rails routes打印 的显示路线在此处输入图像描述

有人可以帮我看看我错过了什么吗?如何使用 RSpec 测试 show 操作的 GET 请求?

标签: ruby-on-railsrspec

解决方案


该错误是由于您没有传递路线所需的 slug 参数引起的:

get :show, slug: contact.slug

但是您首先在这里真正想要的是请求规范而不是控制器规范。请求规范将实际的 HTTP 请求发送到您的应用程序。控制器规范模拟了大部分框架并让错误继续前进 - 尤其是路由错误。

Rails 和 RSpec 团队不鼓励使用控制器规范,不应在遗留代码之外使用。

# spec/requests/api/v1/contacts_spec.rb
require 'rails_helper'

RSpec.describe 'API V1 Contacts', type: :request do

  # This can be DRY:ed into a shared context
  let(:json){ JSON.parse(response.body) }
  subject { response }
  
  # This example uses FactoryBot
  # https://github.com/thoughtbot/factory_bot
  let(:contact) { FactoryBot.create(:contact) }

  # but you could also use a fixture
  let(:contact){ contacts[:one] }
  
  # describe the actual API and not how its implemented
  describe "GET '/api/v1/contacts'" do
    before { get api_vi_contacts_path }
    it { is_expected.to be_successful }
    it "has the correct response attributes" do
      expect(json.keys).to match_array(%w[data included])
    end
  end
  
  describe "GET '/api/v1/contacts/:id'" do
    before { get api_vi_contact_path(contact) }
    it { is_expected.to be_successful }
    # @todo write examples about the JSON
  end
end

推荐阅读