Rspec请求测试遇ActionController::RoutingError:用户更新测试卡壳求助
嘿,我来帮你排查这个ActionController::RoutingError的问题~从你给出的代码来看,主要是测试类型混用和参数结构错误这两个点导致的,咱们一步步来解决:
1. 别同时混用控制器测试和请求测试类型
你在describe里写了type: [:request, :controller],但这两种测试的写法逻辑完全不一样:
- 控制器测试(
type: :controller)是直接调用控制器的动作方法(比如patch :update),不需要设置host,也不用完整URL; - 请求测试(
type: :request)是模拟真实HTTP请求,需要用完整的路径(比如patch "/users/1"),这时候才需要设置host。
混用这两种类型会让Rspec不知道该用哪种测试模式解析你的请求,直接触发路由错误。所以你得二选一:要么写控制器测试,要么写请求测试。
2. 修正参数结构的嵌套问题
你的代码里参数套了两层params:
form_params = { params: { id: 1, email: "hello@example", name: "hello" } } patch :update, params: form_params
这会导致实际传给控制器的参数变成params: { params: { id: 1, ... } },Rails找不到正确的:id参数来匹配路由,自然报错。另外,Rails的strong parameters通常要求用户属性嵌套在user键下(不然控制器会过滤掉这些参数),所以参数结构也要调整。
给你两个修正后的示例
控制器测试写法(推荐如果只是测控制器逻辑)
require 'spec_helper' describe UsersController, type: :controller do # 先创建一个测试用的用户,避免用硬编码的id=1(可能数据库里不存在) let(:test_user) { User.create(email: "original@test.com", name: "Original Name") } describe "#update" do it "doesn't update user with invalid params" do # 直接传正确的参数结构:id + 嵌套在user键下的属性 patch :update, params: { id: test_user.id, user: { email: "hello@example", name: "hello" } } # 重新加载用户数据,断言属性没被修改 test_user.reload expect(test_user.email).not_to eq("hello@example") expect(test_user.name).not_to eq("hello") end end end
请求测试写法(如果要测完整HTTP流程)
require 'spec_helper' describe "User Update Endpoint", type: :request do before(:each) { host! 'localhost:3000' } # 去掉末尾的斜杠,避免路径拼接出问题 let(:test_user) { User.create(email: "original@test.com", name: "Original Name") } it "doesn't update user with invalid params" do # 请求测试要用完整的API路径 patch "/users/#{test_user.id}", params: { user: { email: "hello@example", name: "hello" } } test_user.reload expect(test_user.email).not_to eq("hello@example") # 还可以断言响应状态码,比如expect(response).to have_http_status(:unprocessable_entity) end end
最后再检查两个点
- 确认你的
config/routes.rb里有resources :users,这样Rails才会生成PATCH /users/:id的路由; - 检查
UsersController的update动作是否正确设置了strong parameters,比如:def user_params params.require(:user).permit(:email, :name) end
这样调整后,路由错误应该就能解决啦~
内容的提问来源于stack exchange,提问作者Maayan Naveh
相关产品推荐
相关产品推荐

