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

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

原因分析

  1. 变量名冲突:类B构造函数中,将类A的实例赋值给this.A,与导入的类名A重名,可能导致Jest Mock时出现绑定异常。
  2. 模块导入混用:测试文件使用ES模块的import语法,而类A、B使用CommonJS的require/module.exports语法,Jest在处理跨模块导入时可能出现Mock未生效的情况。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:31:02