Rails 7 命名空间控制器测试失败问题求助
问题描述
在Rails 7项目中为控制器添加api/v1命名空间后,集成测试全部报错,移除命名空间后测试正常,Swagger中API可正常工作。
目录结构
controllers api v1 users_controller.rb
路由配置
Rails.application.routes.draw do mount Rswag::Ui::Engine => '/api-docs' mount Rswag::Api::Engine => '/api-docs' namespace :api do namespace :v1 do resources :users end end #resources :users # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Defines the root path route ("/") # root "articles#index" end
集成测试代码
require "test_helper" class UsersControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:one) end test "should get index" do get users_url, as: :json assert_response :success end test "should create user" do assert_difference("User.count") do post users_url, params: { user: { first_name: "test1", last_name: "test", email: "test@test.com", password: "test12345", is_active: true } }, as: :json end assert_response :created end test "should show user" do get user_url(@user), as: :json assert_response :success end test "should update user" do patch user_url(@user), params: { user: { user: { first_name: "test1", last_name: "test", email: "test@test.com", password: "test12345", is_active: true } } }, as: :json assert_response :success end test "should destroy user" do assert_difference("User.count", -1) do delete user_url(@user), as: :json end assert_response :no_content end end
报错信息
Running 5 tests in a single process (parallelization threshold is 50) Run options: --seed 52765 # Running: E Error: UsersControllerTest#test_should_destroy_user: NoMethodError: undefined method `user_url' for #<UsersControllerTest:0x0000000128b89c68> Did you mean? users test/controllers/users_controller_test.rb:33:in `block (2 levels) in <class:UsersControllerTest>' test/controllers/users_controller_test.rb:32:in `block in <class:UsersControllerTest>' rails test test/controllers/users_controller_test.rb:31 E Error: UsersControllerTest#test_should_update_user: NoMethodError: undefined method `user_url' for #<UsersControllerTest:0x000000012951ddd8> Did you mean? users test/controllers/users_controller_test.rb:27:in `block in <class:UsersControllerTest>' rails test test/controllers/users_controller_test.rb:26 E Error: UsersControllerTest#test_should_show_user: NoMethodError: undefined method `user_url' for #<UsersControllerTest:0x00000001295f7e48> Did you mean? users test/controllers/users_controller_test.rb:22:in `block in <class:UsersControllerTest>' rails test test/controllers/users_controller_test.rb:21 E Error: UsersControllerTest#test_should_get_index: NameError: undefined local variable or method `users_url' for #<UsersControllerTest:0x000000012963dc68> Did you mean? users test/controllers/users_controller_test.rb:9:in `block in <class:UsersControllerTest>' rails test test/controllers/users_controller_test.rb:8 E Error: UsersControllerTest#test_should_create_user: NameError: undefined local variable or method `users_url' for #<UsersControllerTest:0x00000001296771c0> Did you mean? users test/controllers/users_controller_test.rb:15:in `block (2 levels) in <class:UsersControllerTest>' test/controllers/users_controller_test.rb:14:in `block in <class:UsersControllerTest>' rails test test/controllers/users_controller_test.rb:13 Finished in 0.090735s, 55.1055 runs/s, 0.0000 assertions/s. 5 runs, 0 assertions, 0 failures, 5 errors, 0 skips
问题解答
一、users_url这类路由辅助方法的来源
路由辅助方法是Rails根据config/routes.rb中的配置自动生成的,生成的代码临时存放在项目的tmp/routes.rb文件中(无需手动修改)。添加命名空间后,辅助方法名称会带上命名空间前缀,原有的users_url等方法会被替换。
二、解决测试失败的步骤
1. 使用带命名空间的路由辅助方法
添加api/v1命名空间后,路由辅助方法会变为api_v1_users_url和api_v1_user_url,同时修正原测试中参数嵌套错误的问题,修改后的测试代码如下:
require "test_helper" class UsersControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:one) end test "should get index" do get api_v1_users_url, as: :json assert_response :success end test "should create user" do assert_difference("User.count") do post api_v1_users_url, params: { user: { first_name: "test1", last_name: "test", email: "test@test.com", password: "test12345", is_active: true } }, as: :json end assert_response :created end test "should show user" do get api_v1_user_url(@user), as: :json assert_response :success end test "should update user" do patch api_v1_user_url(@user), params: { user: { first_name: "test1", last_name: "test", email: "test@test.com", password: "test12345", is_active: true } }, as: :json assert_response :success end test "should destroy user" do assert_difference("User.count", -1) do delete api_v1_user_url(@user), as: :json end assert_response :no_content end end
2. 验证路由辅助方法名称
执行以下命令可查看所有生成的路由及对应辅助方法:
rails routes
输出中会包含类似条目,第一列的Prefix就是辅助方法前缀,加上_url或_path即为完整方法名:
Prefix Verb URI Pattern Controller#Action api_v1_users GET /api/v1/users(.:format) api/v1/users#index POST /api/v1/users(.:format) api/v1/users#create api_v1_user GET /api/v1/users/:id(.:format) api/v1/users#show PATCH /api/v1/users/:id(.:format) api/v1/users#update PUT /api/v1/users/:id(.:format) api/v1/users#update DELETE /api/v1/users/:id(.:format) api/v1/users#destroy
3. 可选:使用命名空间块简化代码
如果不想重复写命名空间前缀,可在测试中用namespace块包裹请求:
test "should get index" do namespace :api do namespace :v1 do get users_url, as: :json end end assert_response :success end
不过这种写法不如直接使用带前缀的方法直观,推荐优先使用第一种方案。
内容的提问来源于stack exchange,提问作者Krishnadas PC
相关产品推荐
相关产品推荐

