Jest Mock类A时触发TypeError: this.A.getDynamoEntry is not a function
解决Jest Mock类A时出现TypeError: this.A.getDynamoEntry is not a function的问题
问题场景
存在类A和类B,类B的构造函数中实例化类A,并在方法中调用类A的getDynamoEntry方法。编写类B的测试用例时,尝试用Jest Mock类A的方法,但运行测试时触发错误:TypeError: this.A.getDynamoEntry is not a function。
代码示例
测试文件 test.js
import A from '../../src/dao/A' import B from '../../src/dao/B' jest.mock('../../src/dao/A', () => { return jest.fn().mockImplementation(() => { return { getDynamoEntry: jest.fn(()=> Promise.resolve(2)), putDynamoEntry: jest.fn(), updateDynamoEntry: jest.fn(), deleteDynamoEntry: jest.fn() }; }); }); beforeAll(() => { initConfig() }) describe('Test', () => { let entity beforeEach(() => { entity = new B() }) it('getFraudLogosByOwnerId', async () => { const resp = await entity.getFraudLogosByOwnerId(913035121393899) expect(resp).toBe(2) }) })
类A代码
class A { constructor(tableName, dynamoClient) { this.dynamoClient = dynamoClient this.tableName = tableName } async getDynamoEntry(query) { try { return await this.dynamoClient.query(query).promise() } catch (error) { throw error } } async putDynamoEntry(imageEntity) { try { return await this.dynamoClient.put({ TableName: this.tableName, Item: imageEntity }).promise() } catch (error) { throw error } } async updateDynamoEntry(params) { try { return await this.dynamoClient.update(params).promise() } catch (error) { throw error } } async deleteDynamoEntry(criteria) { try { return await this.dynamoClient.delete(criteria).promise() } catch (error) { throw error } } } module.exports = A
类B代码
const dynamoQueryHelper = require('./DynamoQueryHelper') const A = require('./A') class B { constructor() { this.A = new A("table1", "client1") } async getFraudLogosByOwnerId(ownerId) { const query = dynamoQueryHelper.getQuery("123", "table1") try { return await this.A.getDynamoEntry(query) } catch (error) { IPSLogger.logError( error, LogConstants.FRAUD_DATA_ACCESS_DAO, LogConstants.GET_FRAUD_LOGO, ownerId, LogConstants.LOG_GET_FRAUD_IMAGE_BY_OWNER_ID.replace(LogConstants.PLACEHOLDER, ownerId) ) throw error } } } module.exports = B
原因分析
- 变量名冲突:类B构造函数中,将类A的实例赋值给
this.A,与导入的类名A重名,可能导致Jest Mock时出现绑定异常。 - 模块导入混用:测试文件使用ES模块的
import语法,而类A、B使用CommonJS的require/module.exports语法,Jest在处理跨模块导入时可能出现Mock未生效的情况。 - Mock写法细节:虽然遵循了官方文档,但针对CommonJS导出的类,Mock的写法需要确保构造函数被正确替换并返回预期的实例对象。
解决方案
1. 修改类B中的实例变量名
避免实例属性与类名重名,减少潜在冲突:
class B { constructor() { // 将this.A改为this.aInstance this.aInstance = new A("table1", "client1") } async getFraudLogosByOwnerId(ownerId) { const query = dynamoQueryHelper.getQuery("123", "table1") try { // 调用修改后的实例属性 return await this.aInstance.getDynamoEntry(query) } catch (error) { IPSLogger.logError( error, LogConstants.FRAUD_DATA_ACCESS_DAO, LogConstants.GET_FRAUD_LOGO, ownerId, LogConstants.LOG_GET_FRAUD_IMAGE_BY_OWNER_ID.replace(LogConstants.PLACEHOLDER, ownerId) ) throw error } } }
2. 调整Jest Mock的写法
针对CommonJS导出的类,简化Mock逻辑,确保构造函数返回包含Mock方法的对象:
import A from '../../src/dao/A' import B from '../../src/dao/B' // 简化Mock写法,直接返回一个构造函数,实例化后返回预期的Mock对象 jest.mock('../../src/dao/A', () => jest.fn().mockReturnValue({ getDynamoEntry: jest.fn(() => Promise.resolve(2)), putDynamoEntry: jest.fn(), updateDynamoEntry: jest.fn(), deleteDynamoEntry: jest.fn() })); beforeAll(() => { initConfig() }) describe('Test', () => { let entity beforeEach(() => { entity = new B() }) it('getFraudLogosByOwnerId', async () => { const resp = await entity.getFraudLogosByOwnerId(913035121393899) expect(resp).toBe(2) // 验证getDynamoEntry方法被调用 expect(entity.aInstance.getDynamoEntry).toHaveBeenCalled() }) })
3. 统一模块导入方式(可选)
将类A、B的导入方式改为ES模块语法,避免跨模块类型混用:
- 类A修改导出:
export default class A { // ... 原有代码 }
- 类B修改导入:
import dynamoQueryHelper from './DynamoQueryHelper' import A from './A' // ... 原有代码
验证方案
修改完成后重新运行测试,确认:
- 错误
TypeError: this.A.getDynamoEntry is not a function消失 - 测试用例通过,
getFraudLogosByOwnerId方法返回预期的2 - 可以通过
expect(entity.aInstance.getDynamoEntry).toHaveBeenCalled()验证Mock方法被正确调用
内容的提问来源于stack exchange,提问作者Zeeshan Hussain
相关产品推荐
相关产品推荐

