如何在NestJS中对Roles装饰器进行单元测试?
测试NestJS自定义Roles装饰器的方法
测试装饰器的元数据设置逻辑
自定义Roles装饰器本质是通过SetMetadata往目标方法/类上写入元数据,测试时可以用NestJS的Reflector类读取元数据,验证写入是否正确。
示例测试代码:
import { Reflector } from '@nestjs/core'; import { Roles } from './roles.decorator'; describe('Roles Decorator', () => { let reflector: Reflector; beforeEach(() => { reflector = new Reflector(); }); it('应正确设置指定的角色元数据', () => { class TestController { @Roles('admin', 'editor') testMethod() {} } const roles = reflector.get<string[]>('roles', TestController.prototype.testMethod); expect(roles).toEqual(['admin', 'editor']); }); it('空参数时应设置空数组元数据', () => { class TestController { @Roles() testMethod() {} } const roles = reflector.get<string[]>('roles', TestController.prototype.testMethod); expect(roles).toEqual([]); }); });
结合RolesGuard的集成测试
Roles装饰器通常配合权限守卫使用,下面以常见的RolesGuard为例,测试守卫是否根据装饰器的元数据正确判断权限:
假设你的RolesGuard实现如下:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const roles = this.reflector.get<string[]>('roles', context.getHandler()); if (!roles) return true; const request = context.switchToHttp().getRequest(); return roles.some(role => request.user?.roles?.includes(role)); } }
对应的测试代码:
import { Test } from '@nestjs/testing'; import { ExecutionContext } from '@nestjs/common'; import { RolesGuard } from './roles.guard'; import { Reflector } from '@nestjs/core'; describe('RolesGuard 权限验证', () => { let guard: RolesGuard; let reflector: Reflector; beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [RolesGuard, Reflector], }).compile(); guard = moduleRef.get<RolesGuard>(RolesGuard); reflector = moduleRef.get<Reflector>(Reflector); }); it('用户拥有指定角色时应允许请求', () => { const context = { getHandler: jest.fn(), switchToHttp: jest.fn(() => ({ getRequest: jest.fn(() => ({ user: { roles: ['admin'] } })), })), } as unknown as ExecutionContext; jest.spyOn(reflector, 'get').mockReturnValue(['admin']); expect(guard.canActivate(context)).toBe(true); }); it('用户缺少指定角色时应拒绝请求', () => { const context = { getHandler: jest.fn(), switchToHttp: jest.fn(() => ({ getRequest: jest.fn(() => ({ user: { roles: ['user'] } })), })), } as unknown as ExecutionContext; jest.spyOn(reflector, 'get').mockReturnValue(['admin']); expect(guard.canActivate(context)).toBe(false); }); it('未指定角色时应直接允许请求', () => { const context = { getHandler: jest.fn(), switchToHttp: jest.fn(() => ({ getRequest: jest.fn(() => ({}) ) })), } as unknown as ExecutionContext; jest.spyOn(reflector, 'get').mockReturnValue(undefined); expect(guard.canActivate(context)).toBe(true); }); });
关键测试要点
- 单独测试装饰器时,核心是验证
SetMetadata是否正确写入了roles键对应的元数据。 - 集成测试时,重点模拟请求上下文和用户角色信息,验证守卫逻辑是否与装饰器的元数据匹配。
- 可以用Jest的mock方法快速模拟
Reflector的读取行为,减少测试依赖。
内容的提问来源于stack exchange,提问作者Christian Guimarães
相关产品推荐
相关产品推荐

