如何测试使用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
相关产品推荐
相关产品推荐

