使用Jest单元测试TSOA REST端点时,mockResolvedValue调用失败如何解决?
解决Mock TopicEntity.findAll时的"mockResolvedValue is not a function"报错
问题场景
尝试为REST端点编写单元测试时,无法成功Mock TopicEntity.findAll 函数,使用如下测试代码:
import request from 'supertest'; import { app } from '../../main.js'; import { jest } from '@jest/globals'; import { TopicEntity } from '../../db/entity/TopicEntity.js'; jest.mock('../../db/entity/TopicEntity.js'); describe('TopicController', () => { describe('GET /topics', () => { it('should return a list of topics', async () => { // Given const mockTopics = [ { id: 1, name: 'JavaScript' }, { id: 2, name: 'TypeScript' }, ]; (TopicEntity.findAll as jest.Mock).mockResolvedValue(mockTopics as never); // when const response = await request(app).get('/api/topics'); // then expect(response.status).toBe(200); expect(response.body).toEqual(mockTopics); }); }); });
运行后收到报错:
TopicEntity.findAll.mockResolvedValue is not a function TypeError: TopicEntity.findAll.mockResolvedValue is not a function
尝试使用模块工厂Mock对象后仍得到相同结果:
jest.mock('../../db/entity/TopicEntity.js', () => { return { TopicEntity: { findAll: jest.fn(), }, }; });
问题原因
核心问题是TopicEntity是**类(Class)**而非普通对象,直接Mock成普通对象结构无法正确覆盖类的静态方法。无论是自动Mock还是手动Mock,只要没有匹配类的结构,就会导致findAll不是合法的Jest Mock函数。
解决方案
方法1:手动Mock类的静态方法
确保Mock的是类本身,而非普通对象,同时将静态方法findAll定义为Jest Mock函数:
import request from 'supertest'; import { app } from '../../main.js'; import { jest } from '@jest/globals'; import { TopicEntity } from '../../db/entity/TopicEntity.js'; // 手动Mock整个类结构 jest.mock('../../db/entity/TopicEntity.js', () => { const MockTopicEntity = jest.fn(); // 给Mock类挂载静态方法findAll MockTopicEntity.findAll = jest.fn(); return { TopicEntity: MockTopicEntity }; }); describe('TopicController', () => { describe('GET /topics', () => { it('should return a list of topics', async () => { const mockTopics = [ { id: 1, name: 'JavaScript' }, { id: 2, name: 'TypeScript' }, ]; // 直接调用mockResolvedValue,无需额外类型断言 TopicEntity.findAll.mockResolvedValue(mockTopics); const response = await request(app).get('/api/topics'); expect(response.status).toBe(200); expect(response.body).toEqual(mockTopics); // 可选:验证findAll是否被调用 expect(TopicEntity.findAll).toHaveBeenCalled(); }); }); });
方法2:使用自动Mock并修正类型断言
如果偏好Jest的自动Mock功能,需要导入整个模块并正确断言类的类型:
import request from 'supertest'; import { app } from '../../main.js'; import { jest } from '@jest/globals'; // 导入整个模块而非仅TopicEntity import * as TopicEntityModule from '../../db/entity/TopicEntity.js'; // 自动Mock整个模块 jest.mock('../../db/entity/TopicEntity.js'); // 断言Mock后的类类型 const MockTopicEntity = TopicEntityModule.TopicEntity as jest.MockClass<typeof TopicEntityModule.TopicEntity>; describe('TopicController', () => { describe('GET /topics', () => { it('should return a list of topics', async () => { const mockTopics = [ { id: 1, name: 'JavaScript' }, { id: 2, name: 'TypeScript' }, ]; MockTopicEntity.findAll.mockResolvedValue(mockTopics); const response = await request(app).get('/api/topics'); expect(response.status).toBe(200); expect(response.body).toEqual(mockTopics); }); }); });
关键注意点
- 若
TopicEntity是类,必须Mock类的结构,不能直接Mock成普通对象。 - 手动Mock时,确保
findAll是jest.fn()生成的Mock函数,而非普通函数。 - TypeScript环境下,正确的类型断言是避免类型报错和运行时问题的关键。
内容的提问来源于stack exchange,提问作者Stefan Falk
相关产品推荐
相关产品推荐

