使用Jest测试Middy中间件时expect.objectContaining匹配失败
解决Jest测试Middy中间件时expect.objectContaining断言失败的问题
问题场景
测试给AWS Lambda配置的Middy中间件时,该中间件会向request.event添加importantData属性。编写Jest测试用例验证处理器是否收到正确值时,明明参数里包含该属性,但使用expect.objectContaining断言却失败。
相关代码
handler.ts
const main = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { return { statusCode: 200, body: `some` }; }; export const handler = middy(main) .use(myCustomMiddware('somedata'));
myCustomMiddleware.ts
export const myCustomMiddleware = (data: string): middy.MiddlewareObj<APIGatewayProxyEvent, APIGatewayProxyResult> => { const before: middy.MiddlewareFn<APIGatewayProxyEvent, APIGatewayProxyResult> = async (request): Promise<void> => { Object.assign(request.event, { importantData: 'important' } as { importantData: string }); }; return { before }; };
测试代码(原错误版本)
const mockHandler = jest.fn(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { return { statusCode: 200, body: '' }; }); it('event should contain assigned value', async () => { const request = { event: { requestContext: { authorizer: { claims: { 'custom:SomeClaimA': 'claimA', 'custom:SomeClaimB': '1' } } } } }; const middleware = middy(mockHandler).use(myCustomMiddleware('somedata')); await middleware.before(request as never); expect(mockHandler).toHaveBeenCalledWith(expect.objectContaining({ importantData:'important'} )); });
Jest错误输出
Error: expect(jest.fn()).toHaveBeenCalledWith(...expected) Expected: ObjectContaining {"importantData": "important"} Received: {"importantData": "important", "requestContext": {"authorizer": {"claims": {"custom:SomeClaimA": "SomeClaimA", "custom:SomeClaimB": "1"}}}}, {}
原因分析
原测试代码仅调用了middleware.before(request),这只是执行了中间件的before逻辑,修改了request.event,但并没有触发Middy调用mockHandler。mockHandler从未被执行,所以断言toHaveBeenCalledWith必然失败。
解决方案
有两种可行的测试方式:
方案一:直接测试中间件的修改逻辑
直接调用中间件的before函数,验证它是否正确修改了event对象,无需触发完整的handler执行流程:
it('should add importantData to event', async () => { const testEvent = { requestContext: { authorizer: { claims: { 'custom:SomeClaimA': 'claimA', 'custom:SomeClaimB': '1' } } } }; const middleware = myCustomMiddleware('somedata'); await middleware.before({ event: testEvent } as never); expect(testEvent).toEqual(expect.objectContaining({ importantData: 'important' })); });
方案二:触发Middy完整执行流程
通过调用Middy包装后的handler,让它执行完整的生命周期(包括中间件和handler),这样就能断言mockHandler的调用参数:
it('handler should receive event with importantData', async () => { const testEvent = { requestContext: { authorizer: { claims: { 'custom:SomeClaimA': 'claimA', 'custom:SomeClaimB': '1' } } } }; const wrappedHandler = middy(mockHandler).use(myCustomMiddleware('somedata')); await wrappedHandler(testEvent as never, {} as never, jest.fn()); expect(mockHandler).toHaveBeenCalledWith(expect.objectContaining({ importantData: 'important' }), expect.anything(), expect.anything()); });
注意:这里调用wrappedHandler时需要传入三个参数:event、context、callback(可以用jest.fn()模拟),这是Lambda handler的标准签名。
内容的提问来源于stack exchange,提问作者zlZimon
相关产品推荐
相关产品推荐

