Nestjs 单元测试 - 模拟方法守卫
Posted
技术标签:
【中文标题】Nestjs 单元测试 - 模拟方法守卫【英文标题】:Nestjs unit-test - mock method guard 【发布时间】:2019-09-14 19:47:02 【问题描述】:我已经开始使用 NestJS 并且有一个关于嘲笑守卫的问题
用于单元测试。
我正在尝试测试一个基本的 HTTP controller
,它有一个 Guard 附加方法。
当我向 Guard 注入服务时,我的问题就开始了(我需要 Guard 的 ConfigService
)。
运行测试时,DI 无法解析 Guard
● AppController › root › should return "Hello World!"
Nest can't resolve dependencies of the ForceFailGuard (?). Please make sure that the argument at index [0] is available in the _RootTestModule context.
我的力量失败守卫:
import Injectable, CanActivate, ExecutionContext from '@nestjs/common';
import ConfigService from './config.service';
@Injectable()
export class ForceFailGuard implements CanActivate
constructor(
private configService: ConfigService,
)
canActivate(context: ExecutionContext)
return !this.configService.get().shouldFail;
规格文件:
import CanActivate from '@nestjs/common';
import Test, TestingModule from '@nestjs/testing';
import AppController from './app.controller';
import AppService from './app.service';
import ForceFailGuard from './force-fail.guard';
describe('AppController', () =>
let appController: AppController;
beforeEach(async () =>
const mock_ForceFailGuard = CanActivate: jest.fn(() => true) ;
const app: TestingModule = await Test
.createTestingModule(
controllers: [AppController],
providers: [
AppService,
ForceFailGuard,
],
)
.overrideProvider(ForceFailGuard).useValue(mock_ForceFailGuard)
.overrideGuard(ForceFailGuard).useValue(mock_ForceFailGuard)
.compile();
appController = app.get<AppController>(AppController);
);
describe('root', () =>
it('should return "Hello World!"', () =>
expect(appController.getHello()).toBe('Hello World!');
);
);
);
我无法找到有关此问题的示例或文档。我错过了什么还是这是一个真正的问题?
感谢任何帮助, 谢谢。
【问题讨论】:
您找到解决方案了吗?我也面临同样的问题。 以后,请将相关代码粘贴到您的问题中。这使问题成为未来的证明,因为当您更改或删除您链接到的存储库时。这在这种情况下尤其需要,当这个问题是谷歌搜索“nestjs mock guard”时弹出的第一件事。 【参考方案1】:提供的示例 repo 存在 3 个问题:
Nestjs v6.1.1 中存在 .overrideGuard()
的错误 - 请参阅 https://github.com/nestjs/nest/issues/2070
我已确认它已在 6.5.0 中修复。
ForceFailGuard
在providers
中,但它的依赖项(ConfigService
)在创建的TestingModule
中不可用。
如果您想模拟 ForceFailGuard
,只需将其从 providers
中删除,然后让 .overrideGuard()
完成它的工作。
mock_ForceFailGuard
将 CanActivate
作为属性,而不是 canActivate
。
工作示例(nestjs v6.5.0):
import CanActivate from '@nestjs/common';
import Test, TestingModule from '@nestjs/testing';
import AppController from './app.controller';
import AppService from './app.service';
import ForceFailGuard from './force-fail.guard';
describe('AppController', () =>
let appController: AppController;
beforeEach(async () =>
const mock_ForceFailGuard: CanActivate = canActivate: jest.fn(() => true) ;
const app: TestingModule = await Test
.createTestingModule(
controllers: [AppController],
providers: [
AppService,
],
)
.overrideGuard(ForceFailGuard).useValue(mock_ForceFailGuard)
.compile();
appController = app.get<AppController>(AppController);
);
describe('root', () =>
it('should return "Hello World!"', () =>
expect(appController.getHello()).toBe('Hello World!');
);
);
);
【讨论】:
【参考方案2】:如果除了控制器单元测试之外,您还需要/想要对您的自定义保护实现进行单元测试,您可以进行类似于下面的测试,以便预期出现错误等
// InternalGuard.ts
@Injectable()
export class InternalTokenGuard implements CanActivate
constructor(private readonly config: ConfigService)
public async canActivate(context: ExecutionContext): Promise<boolean>
const token = this.config.get('internalToken');
if (!token)
throw new Error(`No internal token was provided.`);
const request = context.switchToHttp().getRequest();
const providedToken = request.headers['authorization'];
if (token !== providedToken)
throw new UnauthorizedException();
return true;
还有你的规范文件
beforeEach(async () =>
const module: TestingModule = await Test.createTestingModule(
controllers: [],
providers: [
InternalTokenGuard,
provide: ConfigService,
useValue:
get: jest.fn((key: string) =>
if (key === 'internalToken')
return 123;
return null;
),
,
,
],
).compile();
config = module.get<ConfigService>(ConfigService);
guard = module.get<InternalTokenGuard>(InternalTokenGuard);
);
it('should throw UnauthorizedException when token is not Bearer', async () =>
const context =
getClass: jest.fn(),
getHandler: jest.fn(),
switchToHttp: jest.fn(() => (
getRequest: jest.fn().mockReturnValue(
headers:
authorization: 'providedToken',
,
),
)),
as any;
await expect(guard.canActivate(context)).rejects.toThrow(
UnauthorizedException,
);
expect(context.switchToHttp).toHaveBeenCalled();
);
【讨论】:
以上是关于Nestjs 单元测试 - 模拟方法守卫的主要内容,如果未能解决你的问题,请参考以下文章