RSpec error ActionController::UrlGenerationError: when testing controller

RSpec error ActionController::UrlGenerationError: when testing controller

我正在为我的 API 控制器编写规范(使用 RSpec)。当我测试索引的 GET 请求时,一切正常,它 returns 预期的主体和成功的响应,但是,当我测试 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 请求?

错误是由于您没有传递路由所需的slug参数造成的:

get :show, slug: contact.slug

但您首先真正想要的是 request spec 而不是控制器规格。请求规范将实际的 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