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

如何在Rails GraphQL中对自定义Type对象进行单元测试

Rails GraphQL自定义Type方法的单元测试方案

完全可以单独测试GraphQL类型中的自定义方法,不需要通过完整查询。这种测试思路和测试模型方法的逻辑一致,属于单元测试范畴,直接针对方法的逻辑验证即可,完全合理。

以下是针对你提供的ScheduleType的具体测试方案:

1. 测试文件结构

把测试文件放在test/graphql/types/schedule_type_test.rb(RSpec项目对应spec/graphql/types/schedule_type_spec.rb),直接继承ActiveSupport::TestCase(或RSpec的RSpec.describe)。

2. 纯逻辑方法测试(如can_edit、available_spots)

这类方法仅依赖object(即Schedule模型实例)的属性或方法,直接实例化ScheduleType并调用方法即可:

require "test_helper"

class Types::ScheduleTypeTest < ActiveSupport::TestCase
  test "#can_edit 返回true当没有注册记录时" do
    schedule = Schedule.new(confirmed_registrations_count: 0)
    # 假设contains_registrations?根据已确认数量判断,直接stub模拟
    schedule.stubs(:contains_registrations?).returns(false)
    type_instance = Types::ScheduleType.new(object: schedule, context: {})

    assert type_instance.can_edit
  end

  test "#can_edit 返回false当存在注册记录时" do
    schedule = Schedule.new(confirmed_registrations_count: 1)
    schedule.stubs(:contains_registrations?).returns(true)
    type_instance = Types::ScheduleType.new(object: schedule, context: {})

    assert_not type_instance.can_edit
  end

  test "#available_spots 计算正确当size已设置" do
    schedule = Schedule.new(size: 10, confirmed_registrations_count: 3)
    type_instance = Types::ScheduleType.new(object: schedule, context: {})

    assert_equal 7, type_instance.available_spots
  end

  test "#available_spots 返回0当注册数超过容量" do
    schedule = Schedule.new(size: 5, confirmed_registrations_count: 8)
    type_instance = Types::ScheduleType.new(object: schedule, context: {})

    assert_equal 0, type_instance.available_spots
  end

  test "#available_spots 返回nil当size未设置" do
    schedule = Schedule.new(size: nil, confirmed_registrations_count: 3)
    type_instance = Types::ScheduleType.new(object: schedule, context: {})

    assert_nil type_instance.available_spots
  end
end

3. 关联加载方法测试(如program)

如果使用了graphql-batch的Loader,返回的是Promise,测试时可以用sync方法获取同步结果,验证Loader是否正确加载关联:

test "#program 通过RecordLoader加载对应Program" do
  program = Program.create!(name: "测试课程")
  schedule = Schedule.new(program_id: program.id)
  type_instance = Types::ScheduleType.new(object: schedule, context: {})

  # 用sync获取Loader返回的Promise结果
  result = type_instance.program.sync
  assert_equal program, result
end

4. 带授权的方法测试(如registrations)

需要模拟上下文的用户信息,验证授权逻辑是否正确触发,同时模拟Loader的返回值:

test "#registrations 验证manage?权限" do
  schedule = Schedule.new
  admin_user = users(:admin) # 从测试 fixtures 取管理员用户
  context = { current_user: admin_user }
  type_instance = Types::ScheduleType.new(object: schedule, context: context)

  # 验证authorize!方法被正确调用
  type_instance.expects(:authorize!).with(schedule, to: :manage?)
  # 模拟Loader返回空注册列表
  Loaders::AssociationLoader.for(Schedule, :registrations)
    .stubs(:load)
    .returns(Promise.resolve([]))

  type_instance.registrations
end

test "#registrations 无权限时抛出错误" do
  schedule = Schedule.new
  student_user = users(:student) # 从测试 fixtures 取普通用户
  context = { current_user: student_user }
  type_instance = Types::ScheduleType.new(object: schedule, context: context)

  # 验证无权限时抛出授权错误
  assert_raises(GraphQL::AuthorizationError) do
    type_instance.registrations
  end
end

关键注意事项

  • 无需启动GraphQL服务器,直接实例化Type类即可完成测试
  • 上下文相关的依赖(如current_user、授权服务)直接通过context哈希传入模拟值
  • Loader类本身的逻辑应该单独测试,Type测试仅需验证是否正确调用了Loader
  • 如果你的BaseObject有全局上下文处理,确保测试时传入必要的上下文参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:55:41