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

如何测试使用GraphQL执行上下文的Nest.js参数装饰器

测试思路验证

你的测试思路完全正确,核心就是构造符合要求的ExecutionContext实例,其中包含对应查询生成的GraphQLResolveInfo对象即可完成测试,不需要启动完整的Apollo服务。

实现步骤

1. 前置依赖准备

你需要用到graphql包自带的工具能力生成真实的GraphQLResolveInfo,不需要手动模拟所有属性:

  • 依赖安装(已安装可跳过):npm install graphql @nestjs/testing jest -D

2. 编写通用工具函数生成模拟上下文

你可以封装一个工具函数,传入查询语句和测试用Schema,自动生成包含对应resolveInfo的ExecutionContext模拟对象:

import { parse, validate, execute, buildSchema } from 'graphql';
import { GqlExecutionContext } from '@nestjs/graphql';
import { ExecutionContext } from '@nestjs/common';

// 构造最小测试用Schema,可根据你的业务字段调整
const testSchema = buildSchema(`
  type User {
    id: ID!
    name: String
    age: Int
  }
  type Query {
    user: User
  }
`);

// 生成模拟ExecutionContext的工具函数
export async function createMockGqlContext(query: string): Promise<ExecutionContext> {
  const document = parse(query);
  // 校验查询合法性
  const errors = validate(testSchema, document);
  if (errors.length > 0) throw new Error(`查询校验失败: ${errors.map(e => e.message).join(',')}`);

  let resolveInfo;
  // 模拟执行查询,捕获resolveInfo对象
  await execute({
    schema: testSchema,
    document,
    rootValue: {
      user: (parent, args, context, info) => {
        resolveInfo = info;
        return { id: '1', name: 'test', age: 18 };
      }
    }
  });

  // 模拟Nest的ExecutionContext
  const mockExecutionCtx = {
    getType: () => 'graphql',
  } as unknown as ExecutionContext;

  //  mock GqlExecutionContext的getInfo方法返回捕获到的resolveInfo
  jest.spyOn(GqlExecutionContext, 'create').mockReturnValue({
    getInfo: () => resolveInfo,
  } as unknown as GqlExecutionContext);

  return mockExecutionCtx;
}

3. 编写单元测试用例

以Jest为例,测试代码如下:

import { GraphQlProjections } from './你的装饰器文件路径';

describe('GraphQlProjections 装饰器测试', () => {
  it('给定查询Query { user { name } },返回正确的字段列表', async () => {
    const testQuery = `Query { user { name } }`;
    const mockCtx = await createMockGqlContext(testQuery);
    const decoratorFn = GraphQlProjections();
    const result = decoratorFn({}, mockCtx);
    // 预期值可根据你的fieldsProjection逻辑调整
    expect(result).toEqual(expect.arrayContaining(['name']));
  });

  it('多字段查询能返回完整字段列表', async () => {
    const testQuery = `Query { user { id name age } }`;
    const mockCtx = await createMockGqlContext(testQuery);
    const decoratorFn = GraphQlProjections();
    const result = decoratorFn({}, mockCtx);
    expect(result).toEqual(expect.arrayContaining(['id', 'name', 'age']));
  });

  it('传入ProjectionOptions参数时能正确过滤字段', async () => {
    const testQuery = `Query { user { id name age } }`;
    const mockCtx = await createMockGqlContext(testQuery);
    // 示例为options支持排除age字段,可根据你的参数规则调整
    const decoratorFn = GraphQlProjections({ exclude: ['age'] });
    const result = decoratorFn({ exclude: ['age'] }, mockCtx);
    expect(result).toEqual(expect.arrayContaining(['id', 'name']));
    expect(result).not.toContain('age');
  });
});
注意事项
  • 如果你的fieldsProjection是第三方依赖,也可以单独mock它的返回值,只测试装饰器的参数传递、上下文获取逻辑是否正确,不需要依赖真实的字段解析逻辑
  • 如果业务Schema很复杂,你可以单独为测试构造最小可用的Schema即可,不需要引入全量业务Schema

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 15:57:04