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

如何在Express API中使用Jest Mock路由内调用的DynamoDB

解决思路

核心原理是利用Jest的模块预Mock能力,在导入Express App实例前就替换掉aws-sdk的导出内容,这样路由文件中初始化的DynamoDB.DocumentClient实例默认就是你Mock的版本,路由执行时调用的DynamoDB方法都会走你定义的Mock逻辑。

具体实现步骤
  1. 固定nanoid的返回值,避免随机生成的URL ID影响测试断言
  2. Mock整个aws-sdk模块,替换DynamoDB.DocumentClient的构造逻辑
  3. 给Mock的DocumentClient实例的get、transactWrite方法绑定自定义实现
  4. 根据测试场景覆盖不同的返回分支(无历史链接/有历史链接/接口报错等)
修改后的test.js完整代码
const request = require('supertest');
// 提前Mock依赖模块,Jest会把这段Mock逻辑提升到所有模块导入之前执行
jest.mock('aws-sdk');
jest.mock('nanoid/async', () => ({
  nanoid: jest.fn(() => Promise.resolve('testid88')) // 固定返回8位测试ID
}));

const AWS = require('aws-sdk');
const app = require('../app');

// 每次测试前重置Mock实例状态
beforeEach(() => {
  AWS.DynamoDB.DocumentClient.mockClear();
});

test('新的长链接应成功生成短链接并返回201', async () => {
  // 获取路由文件中new出来的Mock DocumentClient实例
  const mockDynamoClient = AWS.DynamoDB.DocumentClient.mock.instances[0];
  
  // Mock get方法的实现:模拟当前长链接没有历史存储记录
  mockDynamoClient.get.mockImplementation((params, callback) => {
    callback(null, {}); // 第二个参数返回空对象,代表无匹配记录
  });

  // Mock transactWrite方法的实现:模拟写入成功
  mockDynamoClient.transactWrite.mockImplementation((params, callback) => {
    callback(null);
  });

  const res = await request(app)
    .post('/anon-ops/convert')
    .send({
      longUrl: 'https://google.com',
    })
    .expect(201);

  // 可加额外断言验证返回值
  expect(res.body.convertedUrl).toBe('https://xxxxxxxxxxxx/testid88');
  // 验证Dynamo方法被正确调用
  expect(mockDynamoClient.get).toHaveBeenCalledTimes(1);
  expect(mockDynamoClient.transactWrite).toHaveBeenCalledTimes(1);
});

test('已存在的长链接应直接返回历史短链接', async () => {
  const mockDynamoClient = AWS.DynamoDB.DocumentClient.mock.instances[0];
  
  // Mock get方法返回已有存储记录
  mockDynamoClient.get.mockImplementation((params, callback) => {
    callback(null, {
      Item: {
        userId: 'anonymous',
        originalUrl: 'https://google.com',
        convertedUrl: 'https://xxxxxxxxxxxx/existid1'
      }
    });
  });

  const res = await request(app)
    .post('/anon-ops/convert')
    .send({
      longUrl: 'https://google.com',
    })
    .expect(201);

  expect(res.body.convertedUrl).toBe('https://xxxxxxxxxxxx/existid1');
  // 已有记录的场景下不会调用transactWrite
  expect(mockDynamoClient.transactWrite).not.toHaveBeenCalled();
});
注意事项
  • Jest的jest.mock会被自动提升到文件顶部执行,所以只要写在测试文件里,不管位置在哪,都会在导入app之前完成对aws-sdk的替换
  • 如果要测试报错场景,只需要在Mock方法的callback第一个参数传入Error对象即可,比如callback(new Error('Dynamo error'))就能验证500返回的逻辑
  • 每次测试完成后清空Mock调用记录,避免不同用例之间的状态干扰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 00:51:01