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

Rails API应用:无法正常运行请求类Rspec测试

Rails API 请求类 Rspec 测试问题及解决方案

控制器代码

# frozen_string_literal: true

module Api
  module V1
    class MarketplacesController < ApplicationController
      before_action :authenticate_api_v1_user!
      ...
      def index
        render json: Marketplace.all, status: :ok,
               include: 'url'
      end
      ...
    end
  end
end

三次尝试及问题

第一种尝试:自定义登录方法失败

在辅助文件编写login方法:

# spec/requests_helper.rb 文件
def login(user)
  post api_v1_user_session_path, params: {
    email: user.email, password: user.password
  }.to_json, as: :json
end

测试文件调用:

# spec/requests/api/v1/marketplace_spec.rb 文件
require "rails_helper"
require "requests_helper"

RSpec.describe Marketplace, :type => :request do
  let(:user) { create(:user) }

  context "已登录状态" do
    it "返回所有市场数据" do
      login(user)
      get "/api/v1/marketplaces"

      expect(response.body).not_to include('redirected') # 临时断言,排查重定向HTML问题
    end
  end
end

问题:login返回凭证无效错误,请求体被双重转义:

"{\"email\":\"test_user@test.te\",\"password\":\"password\"}"

用户工厂密码与请求一致,但登录失败,最终请求返回未认证错误:

{"errors":["You need to sign in or sign up before continuing."]}

第二种尝试:使用Devise sign_in辅助方法

改用Devise的sign_in,在spec/rails_helper.rb添加配置:

...
config.include Devise::Test::IntegrationHelpers, type: :request

测试代码:

# spec/requests/api/v1/marketplace_spec.rb 文件
require "rails_helper"
require "requests_helper"

RSpec.describe Marketplace, :type => :request do
  let(:user) { create(:user) }

  context "已登录状态" do
    it "返回所有市场数据" do
      sign_in user
      get "/api/v1/marketplaces"

      expect(response.body).not_to include('redirected') # 临时断言,排查重定向HTML问题
    end
  end
end

问题:请求返回HTML重定向内容,不符合API预期:

<html><body>You are being <a href="http://www.example.com/api/v1/auth/sign_in">redirected</a>.</body></html>

第三种尝试:修改默认URL配置

在config/environments/test.rb添加:

...
config.action_controller.default_url_options = {
  host: 'localhost:3000',
  port: '3000'
}

问题:仍返回HTML重定向,地址改为localhost:3000,但问题未解决。

解决方案

1. 修复自定义登录方法的参数序列化问题

手动to_json导致请求体被双重转义,移除手动序列化,让as: :json自动处理:

# spec/requests_helper.rb 文件
def login(user)
  post api_v1_user_session_path, 
       params: { email: user.email, password: user.password },
       as: :json
end

2. 确保用户工厂正确加密密码

Devise User模型需要password_confirmation来正确加密密码,更新工厂:

# spec/factories/users.rb 文件
FactoryBot.define do
  factory :user, class: 'User' do
    name { 'A user' }
    uid { 'test_user@test.te' }
    email { 'test_user@test.te' }
    password { 'password'}
    password_confirmation { 'password' } # 添加此行
  end
end

3. 配置Devise针对API返回JSON而非重定向

在API的基控制器中重写Devise的认证失败响应,强制返回JSON:

# app/controllers/api/v1/application_controller.rb
module Api
  module V1
    class ApplicationController < ActionController::API
      include Devise::Controllers::Helpers
      protect_from_forgery with: :null_session

      # 重写认证失败逻辑,返回JSON
      def authenticate_api_v1_user!
        unless user_signed_in?
          render json: { errors: ['You need to sign in or sign up before continuing.'] }, 
                 status: :unauthorized
        end
      end

      # 拦截Devise的重定向,针对JSON请求返回错误
      def redirect_to(options = {}, response_options = {})
        if request.format.json?
          render json: { errors: ['You need to sign in or sign up before continuing.'] }, 
                 status: :unauthorized
        else
          super
        end
      end
    end
  end
end

4. 测试中设置正确的请求头(针对sign_in方法)

使用sign_in时,确保请求头指定接受JSON格式,避免服务器返回HTML:

# spec/requests/api/v1/marketplace_spec.rb 文件
require "rails_helper"

RSpec.describe "Marketplaces API", type: :request do
  let(:user) { create(:user) }

  context "已登录状态" do
    it "返回所有市场数据" do
      sign_in user
      get "/api/v1/marketplaces", headers: { 'Accept' => 'application/json' }

      expect(response).to have_http_status(:ok)
      expect(response.content_type).to match(/application\/json/)
      # 添加具体的业务断言
      # expect(JSON.parse(response.body)).to have_key('marketplaces')
    end
  end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:50:35