You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:52:40