Nodejs/NestJS ExceptionFilter Catch 方法的 Jest 单元测试
Posted
技术标签:
【中文标题】Nodejs/NestJS ExceptionFilter Catch 方法的 Jest 单元测试【英文标题】:Jest Unit Test for Nodejs/NestJS ExceptionFilter Catch Method 【发布时间】:2020-03-30 23:22:46 【问题描述】:这是我用 Typescript 为 Nodejs/Nestjs 编写的 BadRequestExceptionFilter
@Catch(BadRequestException)
export class BadRequestExceptionFilter implements ExceptionFilter
constructor(private logger: AppLoggerService)
catch(exception: BadRequestException, host: ArgumentsHost)
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status =
exception instanceof BadRequestException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message =
Title: exception.message.error,
Type: 'Exception - BadRequestExceptionFilter',
Detail: exception.message,
Status: '',
;
this.logger.error(message, '');
response.code(status).send(
statusCode: status,
...(exception.getResponse() as object),
timestamp: 'Exception - BadRequestException' + new Date().toISOString(),
);
这是我的单元测试和 2 断言在这里完成。 第一个 assert 是检查是否调用了 mockLogger.error。这是工作。 第二个断言检查是否调用了 response.code(status).send()。 但得到这个错误。 期望(jest.fn()).toBeCalled()
Expected number of calls: >= 1
Received number of calls: 0
const mockLogger = error: jest.fn() ;
const mockContext: any =
switchToHttp: () => (
getRequest: () => (
url: 'mock-url',
),
getResponse: () =>
const response =
code: jest.fn().mockReturnThis(),
send: jest.fn().mockReturnThis(),
;
return response;
,
),
;
describe('BadRequestExceptionFilter', () =>
let filter: BadRequestExceptionFilter;
beforeEach(() =>
filter = new BadRequestExceptionFilter(mockLogger as any);
);
it('should catch and log the error', () =>
const mockException: BadRequestException = new BadRequestException();
mockException.name = 'BadRequestException';
mockException.getResponse = jest.fn().mockReturnValue(of('getResponse'));
mockException.getStatus = () => 404;
jest.fn(mockContext.switchToHttp().getResponse().send);
filter.catch(mockException, mockContext);
expect(mockLogger.error).toBeCalled();
expect(
mockContext
.switchToHttp()
.getResponse()
.code().send,
).toBeCalled();
);
);
【问题讨论】:
您找到解决方案了吗?我对此有点卡住了。 @tsadkanyitbarek 检查下面我的答案,我已经成功编写测试用例了。 【参考方案1】:在您的过滤器中,您有...(expection.getResponse() as object)
,但exception
上没有函数getResponse()
。相反,您需要先切换到 http 上下文
【讨论】:
【参考方案2】:我做了这样的事情,它奏效了!
export const contextMock = (roles?: string[]) =>
const ctx: any =
ctx.switchToHttp = jest.fn().mockReturnValue(
getRequest: jest.fn().mockReturnValue(requestMock()),
getResponse: jest.fn().mockReturnValue(responseMock()),
)
ctx.getHandler = jest.fn().mockReturnValue( roles ) as Function
return ctx
-----------------------------------------------
const ctxMock = contextMock() as any
expect(ctxMock.switchToHttp).toHaveBeenCalled()
expect(ctxMock.switchToHttp().getResponse).toHaveBeenCalled()
expect(ctxMock.switchToHttp().getResponse().status).toHaveBeenCalled()
expect(ctxMock.switchToHttp().getResponse().json).toHaveBeenCalled()
据我了解,我们总是必须为“期望”传递一个模拟。
【讨论】:
【参考方案3】:我认为使用 Nest 测试模块编写异常过滤器的测试用例很简单。检查下面我是如何实现相同的:
// all-exception.filter.spec.ts
import
Test,
TestingModule
from '@nestjs/testing';
import
HttpStatus,
HttpException
from '@nestjs/common';
import AllExceptionsFilter from './all-exceptions.filter';
import AppLoggerService from '../services/logger/app-logger.service';
const mockAppLoggerService =
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
debug: jest.fn()
;
const mockJson = jest.fn();
const mockStatus = jest.fn().mockImplementation(() => (
json: mockJson
));
const mockGetResponse = jest.fn().mockImplementation(() => (
status: mockStatus
));
const mockHttpArgumentsHost = jest.fn().mockImplementation(() => (
getResponse: mockGetResponse,
getRequest: jest.fn()
));
const mockArgumentsHost =
switchToHttp: mockHttpArgumentsHost,
getArgByIndex: jest.fn(),
getArgs: jest.fn(),
getType: jest.fn(),
switchToRpc: jest.fn(),
switchToWs: jest.fn()
;
describe('System header validation service', () =>
let service: AllExceptionsFilter;
beforeEach(async () =>
jest.clearAllMocks();
const module: TestingModule = await Test.createTestingModule(
providers: [
AllExceptionsFilter,
provide: AppLoggerService,
useValue: mockAppLoggerService
,
]
).compile();
service = module.get<AllExceptionsFilter>(AllExceptionsFilter);
);
describe('All exception filter tests', () =>
it('should be defined', () =>
expect(service).toBeDefined();
);
it('Http exception', () =>
service.catch(
new HttpException('Http exception', HttpStatus.BAD_REQUEST),
mockArgumentsHost
);
expect(mockHttpArgumentsHost).toBeCalledTimes(1);
expect(mockHttpArgumentsHost).toBeCalledWith();
expect(mockGetResponse).toBeCalledTimes(1);
expect(mockGetResponse).toBeCalledWith();
expect(mockStatus).toBeCalledTimes(1);
expect(mockStatus).toBeCalledWith(HttpStatus.BAD_REQUEST);
expect(mockJson).toBeCalledTimes(1);
expect(mockJson).toBeCalledWith(
message: 'Http exception'
);
);
);
);
【讨论】:
当我尝试运行此测试时,我得到一个 ctx.getRequest() is not a function。知道为什么吗? @iAviator 我已经编辑了上面的代码模拟 getRequest fn 添加。您可以将 jest.fn() 替换为您的自定义模拟以上是关于Nodejs/NestJS ExceptionFilter Catch 方法的 Jest 单元测试的主要内容,如果未能解决你的问题,请参考以下文章