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

Jest入门:如何测试依赖无法实例化Session类参数的异步函数?

你好!这种场景在单元测试里太常见了,完全可以通过 Mock Session 类的实例来解决,不用纠结无法创建真实实例的问题。下面我一步步给你讲怎么实现:

核心思路:Mock 依赖而非使用真实实例

我们不需要真实的 Session 实例,只需要构建一个符合函数调用需求的假对象——也就是 Mock 出 initFlow 里用到的 Session 属性和方法即可,比如 userInput.getParam、features.useTerms、botId 这些。同时,还要把函数里依赖的其他模块(AtomManager、UserManager 等)也 Mock 掉,确保测试只聚焦于 initFlow 本身的逻辑。


具体实现步骤

1. 构建 Mock Session 对象

根据 initFlow 里用到的 Session 成员,创建一个包含对应属性和 Mock 方法的对象:

// 如果你用 TypeScript,最后可以用 as unknown as Session 做类型断言
const mockSession = {
  userInput: {
    getParam: jest.fn() // Mock getParam 方法
  },
  features: {
    useTerms: false // 可根据测试场景切换 true/false
  },
  botId: 'test-bot-id',
  user: null // 后续测试中可动态修改
};

2. Mock 依赖的外部模块

initFlow 里调用了 AtomManager、UserManager 等模块的方法,单元测试需要隔离这些外部依赖,用 Jest 直接 Mock 整个模块:

// Mock AtomManager
jest.mock('./path/to/AtomManager', () => ({
  findActiveAtom: jest.fn(),
  getStartAtom: jest.fn()
}));

// Mock UserManager
jest.mock('./path/to/UserManager', () => ({
  getGlobalUser: jest.fn()
}));

// Mock AtomProcessor
jest.mock('./path/to/AtomProcessor', () => ({
  processAtom: jest.fn()
}));

3. 编写不同分支的测试用例

针对 initFlow 的各个逻辑分支,编写对应的测试:

describe('initFlow', () => {
  // 每次测试前重置所有 Mock 的调用记录和返回值
  beforeEach(() => {
    jest.clearAllMocks();
  });

  // 测试分支1:存在 nextAtomId 且满足条件时,返回 processAtom 的结果
  it('should return processAtom result when valid nextAtomId exists', async () => {
    // 1. 设置 Mock 返回值
    const mockNextAtomId = 'test-atom-123';
    const mockNextAtom = { id: mockNextAtomId, type: 'beforeTerms' };
    const mockProcessResult = { status: 'success' };

    mockSession.userInput.getParam.mockReturnValue(mockNextAtomId);
    AtomManager.findActiveAtom.mockResolvedValue(mockNextAtom);
    AtomProcessor.processAtom.mockResolvedValue(mockProcessResult);

    // 2. 调用被测函数
    const result = await initFlow(mockSession);

    // 3. 断言逻辑正确性
    expect(AtomManager.findActiveAtom).toHaveBeenCalledWith(mockNextAtomId);
    expect(AtomProcessor.processAtom).toHaveBeenCalledWith(mockSession, mockNextAtom);
    expect(result).toEqual(mockProcessResult);
  });

  // 测试分支2:不存在 nextAtomId 时,使用起始 atom 并初始化用户
  it('should use start atom and initialize user when no nextAtomId', async () => {
    // 设置 Mock:getParam 返回 null,模拟无 nextAtomId 的情况
    mockSession.userInput.getParam.mockReturnValue(null);
    const mockStartAtom = { id: 'start-atom', type: 'default' };
    const mockUser = { id: 'test-user-456' };
    const mockProcessResult = { status: 'started' };

    AtomManager.getStartAtom.mockResolvedValue(mockStartAtom);
    UserManager.getGlobalUser.mockResolvedValue(mockUser);
    AtomProcessor.processAtom.mockResolvedValue(mockProcessResult);

    const result = await initFlow(mockSession);

    expect(AtomManager.getStartAtom).toHaveBeenCalledWith(mockSession.botId);
    expect(UserManager.getGlobalUser).toHaveBeenCalledWith(mockSession);
    expect(mockSession.user).toEqual(mockUser);
    expect(AtomProcessor.processAtom).toHaveBeenCalledWith(mockSession, mockStartAtom);
    expect(result).toEqual(mockProcessResult);
  });

  // 测试分支3:找不到起始 atom 时抛出错误
  it('should throw error when start atom is not found', async () => {
    mockSession.userInput.getParam.mockReturnValue(null);
    AtomManager.getStartAtom.mockResolvedValue(null);

    // 断言函数抛出指定错误
    await expect(initFlow(mockSession)).rejects.toThrow('Could not find start atom');
    expect(AtomManager.getStartAtom).toHaveBeenCalledWith(mockSession.botId);
  });
});

TypeScript 类型兼容小技巧

如果用 TypeScript,直接用 Mock 对象可能会报类型错误,这时候可以用两种方式解决:

  1. 用 as unknown as Session 对 Mock 对象做类型断言
  2. 直接 Mock 整个 Session 类,生成类型兼容的实例:
jest.mock('./path/to/Session', () => {
  return jest.fn().mockImplementation(() => ({
    userInput: { getParam: jest.fn() },
    features: { useTerms: false },
    botId: 'test-bot-id',
    user: null
  }));
});

// 创建类型兼容的 Mock 实例
const mockSession = new Session() as jest.Mocked<Session>;

内容的提问来源于stack exchange,提问作者dragalur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 21:12:33