In RSpec, running a patch or put test will result in an ActionController::UrlGenerationError: No route matches error
In RSpec, running a patch or put test will result in an ActionController::UrlGenerationError: No route matches error
我想解决的问题
我希望 Rspec 补丁或测试成功。
之前我也测试过PostsContoroller,很纳闷,因为我在测试PostsContoroller的时候没有报同样的错误。
错误
Failures:
1) Api::V1::PostItemsController update Update Content
Failure/Error: patch :update, params: { post: post_params }
ActionController::UrlGenerationError:
No route matches {:action=>"update", :controller=>"api/v1/post_items", :post=>{:id=>1, :content=>"Update-Content", :status=>false, :post_id=>1}}
# ./spec/controllers/post_items_spec.rb:11:in `block (3 levels) in <main>'
Finished in 0.35529 seconds (files took 5.58 seconds to load)
5 examples, 1 failure
代码
工厂机器人
book.rb
FactoryBot.define do
factory :book, class: Post do
sequence(:id) { |n| n}
sequence(:title) { |n| "title#{n}" }
sequence(:author) { |n| "author#{n}" }
sequence(:image) { |n| "image#{n}"}
end
end
content.rb
FactoryBot.define do
factory :content, class: PostItem do
sequence(:id) { |n| n }
sequence(:content) { |n| "list#{n}"}
sequence(:status) { false }
end
end
规格
post_items_spec.rb
require 'rails_helper'
RSpec.describe Api::V1::PostItemsController, type: :controller do
describe 'update' do
it 'Update Content' do
book = create(:book)
content = create(:content, post_id: book.id)
post_params = { id: content.id, content: 'Update-Content', status: false, post_id: book.id }
patch :update, params: { post: post_params }
json = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(json['Update-Content']).to eq('Update-content')
end
end
end
路线
**Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :posts
resources :post_items
end
end
end
Rails 和 RSpec 团队都不鼓励使用控制器规范,并且已经存在很长时间了。您应该编写请求规范,而不是发送真正的 HTTP 请求。
RSpec.describe 'Api V1 Post items', type: :request do
let(:book) { create(:book) }
describe "PATCH /api/v1/books" do
context "with valid parameters" do
subject do
patch api_v1_post_item_path(book),
params: { content: 'Update-Content' }
end
it { should be_successful }
it "updates the content" do
# refresh the record from the db
expect { book.reload }.to change(book, :title).to('Update-Content')
end
it "includes the updated entity in the response body" do
expect(response.parsed_body['content']).to eq 'Update-Content'
end
end
# @todo write specs with invalid parameters
# @todo write specs for authentication and authorization
end
end
另一个问题是您在工厂中生成 ID。永远不要这样做。当您实际保留记录时,数据库将自动分配 ID。当您使用 build_stubbed
时,FactoryBot 将创建一个模拟 ID。使用序列生成 ID 会带来不良做法,例如将 ID 硬编码到规范中,只会让您头疼。
如果您真的想挽救该控制器规范,路由错误是由于您缺少 ID 参数这一事实引起的 - 因为您将其称为 patch :update, params: { post: post_params }
,id 参数被埋在params[:post][:id]
。所以你想要 patch :update, params: { id: post.id, post: post_params }
虽然我不推荐这个 - 开始使用程序并编写未来的证明测试,而不是让所有的错误都溜走。
我想解决的问题
我希望 Rspec 补丁或测试成功。 之前我也测试过PostsContoroller,很纳闷,因为我在测试PostsContoroller的时候没有报同样的错误。
错误
Failures:
1) Api::V1::PostItemsController update Update Content
Failure/Error: patch :update, params: { post: post_params }
ActionController::UrlGenerationError:
No route matches {:action=>"update", :controller=>"api/v1/post_items", :post=>{:id=>1, :content=>"Update-Content", :status=>false, :post_id=>1}}
# ./spec/controllers/post_items_spec.rb:11:in `block (3 levels) in <main>'
Finished in 0.35529 seconds (files took 5.58 seconds to load)
5 examples, 1 failure
代码
工厂机器人
book.rb
FactoryBot.define do
factory :book, class: Post do
sequence(:id) { |n| n}
sequence(:title) { |n| "title#{n}" }
sequence(:author) { |n| "author#{n}" }
sequence(:image) { |n| "image#{n}"}
end
end
content.rb
FactoryBot.define do
factory :content, class: PostItem do
sequence(:id) { |n| n }
sequence(:content) { |n| "list#{n}"}
sequence(:status) { false }
end
end
规格
post_items_spec.rb
require 'rails_helper'
RSpec.describe Api::V1::PostItemsController, type: :controller do
describe 'update' do
it 'Update Content' do
book = create(:book)
content = create(:content, post_id: book.id)
post_params = { id: content.id, content: 'Update-Content', status: false, post_id: book.id }
patch :update, params: { post: post_params }
json = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(json['Update-Content']).to eq('Update-content')
end
end
end
路线
**Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :posts
resources :post_items
end
end
end
Rails 和 RSpec 团队都不鼓励使用控制器规范,并且已经存在很长时间了。您应该编写请求规范,而不是发送真正的 HTTP 请求。
RSpec.describe 'Api V1 Post items', type: :request do
let(:book) { create(:book) }
describe "PATCH /api/v1/books" do
context "with valid parameters" do
subject do
patch api_v1_post_item_path(book),
params: { content: 'Update-Content' }
end
it { should be_successful }
it "updates the content" do
# refresh the record from the db
expect { book.reload }.to change(book, :title).to('Update-Content')
end
it "includes the updated entity in the response body" do
expect(response.parsed_body['content']).to eq 'Update-Content'
end
end
# @todo write specs with invalid parameters
# @todo write specs for authentication and authorization
end
end
另一个问题是您在工厂中生成 ID。永远不要这样做。当您实际保留记录时,数据库将自动分配 ID。当您使用 build_stubbed
时,FactoryBot 将创建一个模拟 ID。使用序列生成 ID 会带来不良做法,例如将 ID 硬编码到规范中,只会让您头疼。
如果您真的想挽救该控制器规范,路由错误是由于您缺少 ID 参数这一事实引起的 - 因为您将其称为 patch :update, params: { post: post_params }
,id 参数被埋在params[:post][:id]
。所以你想要 patch :update, params: { id: post.id, post: post_params }
虽然我不推荐这个 - 开始使用程序并编写未来的证明测试,而不是让所有的错误都溜走。