You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:32:20