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

使用Jest编写JS异步函数单元测试:Mock及authClient报错解决

解决Jest测试异步函数时authClient is not defined的问题及完整测试方案

先修复代码中的基础问题

你的代码存在几个语法/导出问题,这是导致报错的直接原因:

  1. myClientManager.js:

    • 模块名拼写错误:@microsoft/mirosoft-graph-client → @microsoft/microsoft-graph-client
    • 未导出authClient函数,需添加导出语句
    • 缺少闭合括号,补全函数结构
      修复后代码:
    const graph = require('@microsoft/microsoft-graph-client');
    require('isomorphic-fetch');
    
    const authClient = (accessToken) => {
      return graph.Client.init({
        authProvider: (done) => {
          done(null, accessToken);
        }
      });
    };
    
    module.exports = { authClient };
    
  2. myClient.js:

    • req.header应为req.headers(拼写错误)
    • 括号不匹配:authClient(req.header['px-token']; 缺少闭合括号
    • 假设conFigItem是项目配置变量,测试时会Mock它
      修复后代码:
    const { authClient } = require("../service/gMemry"); // 确保路径正确,gMemry应为导出authClient的文件名(比如myClientManager.js改名为gMemry.js)
    
    const getResource = async (req, res) => {
      try {
        const gMemory = authClient(req.headers['px-token']);
        const result = await gMemory.api(conFigItem.auth.clientId).get();
        if (!result) {
          return res.sendStatus(401).send();
        }
        res.send({ result });
      } catch (e) {
        res.sendStatus(401).send({ result: null });
      }
    };
    
    module.exports = { getResource };
    

编写Jest单元测试的步骤

1. Mock依赖模块

在测试文件中Mock../service/gMemry模块的authClient函数,以及它返回的Graph客户端对象的方法,避免调用真实第三方服务。

2. 模拟请求和响应对象

创建Mock的req和res对象,其中res的sendStatus、send方法用jest.fn()模拟,方便后续断言调用情况。

3. 编写测试用例

覆盖成功返回结果、无结果返回401、捕获异常返回401三种核心场景。

完整的myClient.spec.js代码:

const { getResource } = require("./myClient"); // 导入正确路径
const { authClient } = require("../service/gMemry");

// Mock整个gMemry模块
jest.mock("../service/gMemry", () => ({
  authClient: jest.fn()
}));

describe('getResource', () => {
  // 每次测试前重置Mock函数,避免测试间副作用
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('成功获取资源时返回结果', async () => {
    // 模拟authClient返回的客户端对象链式调用
    const mockApi = jest.fn().mockReturnThis();
    const mockGet = jest.fn().mockResolvedValue({ data: 'test-resource' });
    authClient.mockReturnValue({
      api: mockApi,
      get: mockGet
    });

    // 模拟请求、响应对象
    const mockReq = {
      headers: {
        'px-token': 'valid-token'
      }
    };
    const mockRes = {
      sendStatus: jest.fn().mockReturnThis(),
      send: jest.fn()
    };
    // Mock全局配置变量
    global.conFigItem = {
      auth: {
        clientId: 'test-client-id'
      }
    };

    await getResource(mockReq, mockRes);

    // 断言各方法调用正确性
    expect(authClient).toHaveBeenCalledWith('valid-token');
    expect(mockApi).toHaveBeenCalledWith('test-client-id');
    expect(mockGet).toHaveBeenCalled();
    expect(mockRes.send).toHaveBeenCalledWith({ result: { data: 'test-resource' } });
    expect(mockRes.sendStatus).not.toHaveBeenCalled();
  });

  it('获取结果为空时返回401', async () => {
    const mockApi = jest.fn().mockReturnThis();
    const mockGet = jest.fn().mockResolvedValue(null);
    authClient.mockReturnValue({
      api: mockApi,
      get: mockGet
    });

    const mockReq = {
      headers: {
        'px-token': 'valid-token'
      }
    };
    const mockRes = {
      sendStatus: jest.fn().mockReturnThis(),
      send: jest.fn()
    };
    global.conFigItem = {
      auth: {
        clientId: 'test-client-id'
      }
    };

    await getResource(mockReq, mockRes);

    expect(mockRes.sendStatus).toHaveBeenCalledWith(401);
    expect(mockRes.send).toHaveBeenCalled();
  });

  it('捕获异常时返回401', async () => {
    const mockApi = jest.fn().mockReturnThis();
    const mockGet = jest.fn().mockRejectedValue(new Error('Auth failed'));
    authClient.mockReturnValue({
      api: mockApi,
      get: mockGet
    });

    const mockReq = {
      headers: {
        'px-token': 'invalid-token'
      }
    };
    const mockRes = {
      sendStatus: jest.fn().mockReturnThis(),
      send: jest.fn()
    };
    global.conFigItem = {
      auth: {
        clientId: 'test-client-id'
      }
    };

    await getResource(mockReq, mockRes);

    expect(mockRes.sendStatus).toHaveBeenCalledWith(401);
    expect(mockRes.send).toHaveBeenCalledWith({ result: null });
  });
});

关键知识点说明

  • Jest.mock():Mock整个依赖模块,隔离真实第三方服务调用
  • jest.fn():创建Mock函数,用于模拟方法行为并断言调用次数、参数、返回值
  • async/await:处理异步函数测试,确保测试等待异步操作完成后再执行断言
  • beforeEach:在每个测试用例前重置Mock状态,避免测试间的干扰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 11:47:48