如何使用Jest测试对接DynamoDB的Express Serverless接口
解决方案
你遇到的问题本质是单元测试默认对接了云端DynamoDB导致的,和你用Express框架没有冲突,以下两种方案都可以解决:
方案一:Mock DynamoDB客户端(单元测试首选,轻量无需额外服务)
直接用Jest模拟AWS SDK的DynamoDB DocumentClient实例,拦截数据库请求返回预设值,不需要真的连接任何远端/本地数据库,适合纯业务逻辑验证。
操作步骤:
- 首先在测试文件中Mock
aws-sdk模块,同时建议Mock异步生成urlId的nanoid方法,避免随机值影响断言:
const request = require('supertest'); const AWS = require('aws-sdk'); const { nanoid } = require('nanoid/async'); const app = require('../app'); // Mock nanoid固定返回值 jest.mock('nanoid/async', () => ({ nanoid: jest.fn().mockResolvedValue('test1234') })); // Mock DynamoDB DocumentClient的方法 const mockGet = jest.fn(); const mockTransactWrite = jest.fn(); AWS.DynamoDB.DocumentClient = jest.fn(() => ({ get: mockGet, transactWrite: mockTransactWrite })); // 每个测试用例前清空mock调用记录 beforeEach(() => { mockGet.mockClear(); mockTransactWrite.mockClear(); });
- 针对你当前的测试用例,补充不同场景的返回模拟:
// 场景1:数据库中不存在该长链,需要新增记录 test('Should convert new url from anonymous user ', async () => { // 模拟get方法返回空结果(不存在该长链) mockGet.mockImplementation((params, callback) => { callback(null, {}); }); // 模拟transactWrite执行成功 mockTransactWrite.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/test1234'); // 可选:断言DynamoDB方法被调用的参数符合预期 expect(mockGet).toHaveBeenCalledWith(expect.objectContaining({ Key: { userId: 'anonymous', originalUrl: 'https://google.com' } }), expect.any(Function)); }); // 场景2:数据库中已存在该长链,直接返回已有短链 test('Should return existed converted url for duplicate longUrl', async () => { // 模拟get方法返回已有记录 mockGet.mockImplementation((params, callback) => { callback(null, { Item: { userId: 'anonymous', originalUrl: 'https://google.com', convertedUrl: 'https://xxxxxxxxxxxx/exist123' } }); }); const res = await request(app) .post('/anon-ops/convert') .send({ longUrl: 'https://google.com', }) .expect(201); expect(res.body.convertedUrl).toBe('https://xxxxxxxxxxxx/exist123'); // 验证这种场景下不会调用写入方法 expect(mockTransactWrite).not.toHaveBeenCalled(); });
方案二:使用本地DynamoDB做集成测试(适合需要验证真实数据库操作的场景)
如果需要真的运行DynamoDB读写逻辑验证完整性,可以本地启动DynamoDB Local服务,测试时将SDK的连接指向本地实例。
操作步骤:
- 本地启动DynamoDB Local,推荐用Docker一键启动:
docker run -p 8000:8000 amazon/dynamodb-local - 在Jest的全局配置文件(或测试文件开头)修改AWS SDK的默认配置,指向本地DynamoDB:
const AWS = require('aws-sdk'); AWS.config.update({ region: 'local', endpoint: 'http://localhost:8000', accessKeyId: 'fakeAccessKey', secretAccessKey: 'fakeSecretKey' });
- 测试前提前在本地DynamoDB中创建和线上同名的测试表,测试完成后可以清空测试数据,不会影响线上环境。
注意:如果你的代码中已经硬编码了DynamoDB实例的配置,可以把实例化逻辑抽成可配置的公共模块,测试时直接替换配置即可,不需要修改业务代码。
内容的提问来源于stack exchange,提问作者Jatin Mehrotra
相关产品推荐
相关产品推荐

