如何在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
相关产品推荐
相关产品推荐

