如何使用Jest模拟DynamoDB的Promise返回(不依赖第三方库)
无第三方库模拟DynamoDB Promise返回方案
问题根源
你当前的测试Mock是针对回调形式的DynamoDB调用实现的,但业务代码中使用的是AWS SDK提供的.promise()链式调用语法,Mock结构与实际调用逻辑不匹配,所以无法正常模拟返回。
核心实现逻辑
不需要引入任何第三方依赖,仅需对齐AWS SDK的调用结构即可:调用DynamoDB操作方法(get/transactWrite等)后会返回一个带有promise方法的对象,调用该方法会返回对应结果的Promise实例,按照这个结构写Mock就行。
修正后的测试代码
const request = require('supertest'); describe('Test for Authenticated Url', () => { beforeEach(() => { jest.resetModules(); // 固定nanoid返回值,方便断言 jest.mock('nanoid/async', () => ({ nanoid: jest.fn(() => Promise.resolve('test1234')) })); }); test('应该返回已存在的转换链接', async () => { const mockedDocumentClient = { get: jest.fn(), transactWrite: jest.fn(), }; const mockedDynamoDB = { DocumentClient: jest.fn(() => mockedDocumentClient), }; jest.doMock('aws-sdk', () => ({ DynamoDB: mockedDynamoDB })); // 模拟get方法返回已有记录 mockedDocumentClient.get.mockImplementation(() => ({ promise: () => Promise.resolve({ Item: { convertedUrl: 'xyz', }, }) })); // 模拟transactWrite方法执行成功 mockedDocumentClient.transactWrite.mockImplementation(() => ({ promise: () => Promise.resolve() })); const app = require('../app'); const response = await request(app).post('/').send({ longUrl: 'https://google.com', }); expect(response.body).toMatchObject({ convertedUrl: 'xyz' }); expect(response.statusCode).toBe(201); }); test('新链接应该生成并返回新转换链接', async () => { const mockedDocumentClient = { get: jest.fn(), transactWrite: jest.fn(), }; const mockedDynamoDB = { DocumentClient: jest.fn(() => mockedDocumentClient), }; jest.doMock('aws-sdk', () => ({ DynamoDB: mockedDynamoDB })); // 模拟get方法返回空(无匹配记录) mockedDocumentClient.get.mockImplementation(() => ({ promise: () => Promise.resolve({}) })); mockedDocumentClient.transactWrite.mockImplementation(() => ({ promise: () => Promise.resolve() })); const app = require('../app'); const response = await request(app).post('/').send({ longUrl: 'https://google.com', }); expect(response.body).toMatchObject({ convertedUrl: 'https://trimify.awssensei.tk/test1234' }); expect(response.statusCode).toBe(201); }); test('Dynamo报错时应该返回500错误', async () => { const mockedDocumentClient = { get: jest.fn(), }; const mockedDynamoDB = { DocumentClient: jest.fn(() => mockedDocumentClient), }; jest.doMock('aws-sdk', () => ({ DynamoDB: mockedDynamoDB })); // 模拟get方法抛出异常 mockedDocumentClient.get.mockImplementation(() => ({ promise: () => Promise.reject(new Error('连接失败')) })); const app = require('../app'); const response = await request(app).post('/').send({ longUrl: 'https://google.com', }); expect(response.statusCode).toBe(500); expect(response.body.error).toBe('Unknown Server Error, Please Trimify Again!'); }); });
补充说明
如果需要同时兼容回调和promise两种调用方式,可以在mock实现里加判断:有传回调就执行回调,同时返回带promise方法的对象即可,不需要修改现有业务逻辑。
内容的提问来源于stack exchange,提问作者Jatin Mehrotra
相关产品推荐
相关产品推荐

