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

如何用RSpec测试PUT/PATCH API?更新记录未生效排查

Rails RSpec PUT/PATCH 测试中记录未更新的问题排查

我正在测试API的PUT/PATCH端点,但测试里的record_to_update没有按预期更新。用Postman测试同一个端点是正常的,使用Rails 5.2和RSpec 3.8编写的测试代码如下:

require 'rails_helper'
RSpec.describe UsersController, type: :controller do
  context 'when request with no valid headers' do
    ... ... ...
  end
  context 'when resquest with valid headers' do
    before do
      request.accept = 'application/vnd.api+json'
      request.content_type = 'application/vnd.api+json'
      2.times do
        create(:user)
      end
    end
    describe 'PATCH/PUT /users/:id' do
      let(:record_to_update) { create(:user) }
      let(:user_params) do
        { id: first_user.id, name: 'goku', email: 'goku@bol.com' }
      end
      before do
        put :update, params: { id: record_to_update, user: user_params }
        record_to_update.reload
      end
      it 'should update user' do
        expect(record_to_update.name).to eq('goku')
        expect(response.status).to eq 200
      end
    end
  end
end

问题原因分析

我帮你梳理下测试代码里的几个关键错误:

  • 参数结构与目标ID错误:你在user_params里误用了未定义的first_user.id,而且没必要在更新参数里传递id——Rails的update动作是通过URL参数里的id(也就是params[:id])来定位要修改的记录的,额外传递的id要么被控制器的strong params过滤,要么会干扰更新逻辑。
  • 请求参数传递不规范:调用put :update时,你直接传了record_to_update(User对象)作为id参数,虽然Rails可能会自动转成ID,但更关键的是你把包含错误ID的user_params传给了user参数,导致控制器可能在更新错误的记录,或者参数被过滤后没有实际更新字段。

修复后的测试代码

require 'rails_helper'
RSpec.describe UsersController, type: :controller do
  context 'when request with no valid headers' do
    ... ... ...
  end
  context 'when request with valid headers' do
    before do
      request.accept = 'application/vnd.api+json'
      request.content_type = 'application/vnd.api+json'
      2.times do
        create(:user)
      end
    end
    describe 'PATCH/PUT /users/:id' do
      let(:record_to_update) { create(:user) }
      # 只传递需要更新的字段,移除多余的id参数
      let(:user_params) do
        { name: 'goku', email: 'goku@bol.com' }
      end
      before do
        # 明确传递目标记录的ID,参数结构符合控制器预期
        put :update, params: { id: record_to_update.id, user: user_params }
        record_to_update.reload
      end
      it 'should update user' do
        expect(record_to_update.name).to eq('goku')
        expect(response.status).to eq 200
      end
    end
  end
end

额外检查点

除了测试代码,还要确认你的UsersController里的逻辑是否正确:

  1. 确保update动作正确通过params[:id]查找记录:
def update
  @user = User.find(params[:id])
  if @user.update(user_params)
    render json: @user, status: :ok
  else
    render json: @user.errors, status: :unprocessable_entity
  end
end
  1. 确认strong params允许更新name和email字段:
private

def user_params
  params.require(:user).permit(:name, :email)
end

如果控制器的strong params没有包含要更新的字段,即使请求参数正确,也不会修改记录,这也是Postman能成功但测试失败的潜在原因之一。

内容的提问来源于stack exchange,提问作者Lucas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:26:10