【问题标题】:Jest - mock a set of functions on a destructured moduleJest - 在解构模块上模拟一组函数
【发布时间】:2026-01-03 15:30:01
【问题描述】:

我们在私有存储库中有自定义库,它接受来自 AWS Secrets Manager 的 secretId 并返回初始化的 knex 连接。

代码如下:

// mysql.js
async function getConnection (secretId, dbname) {
    AWS.config.update({region:process.env.REGION}) 
    const secretsManager = new AWS.SecretsManager() 

    let secret
    console.log(`Getting secret from ${secretId}`) 
    try {
        const secretValue = await secretsManager.getSecretValue({
            SecretId: secretId
        }).promise() 

        secret = JSON.parse(secretValue.SecretString)
    } catch (e) {
        console.log(`Error: Unable to get secret from ${secretId}`)
        return null
    }

    console.log(`Initialzing a connection to ${secret.proxyendpoint}:${secret.port}/${dbname} as ${secret.username}`)
    const knex = require('knex')(
        {
            client: 'mysql2',
            connection: {
                host: secret.proxyendpoint,
                user: secret.username,
                database: dbname,
                port: secret.port,
                ssl: 'Amazon RDS',
                password: secret.password
            }
        }
    )
    return knex
}

库导出函数,因此可以以解构方式使用它:

// index.js
exports.mysql = require('./mysql');

这里正在使用它:

    // conn.js
    const {mysql} = require('@org/knex-conn');

    const connection = await mysql.getConnection(secretId, dbName);
    
    await connection
        .select('col1', 'col2', 'col3')
        .from('table')
        .then((rows) => {
            console.log(`${row['col1']} ${row['col2']} ${row['col3']}`);
        })
        .catch((err) => {
            console.log( err); throw err
        })
        .finally(() => {
            connection.destroy();
        });

在另一个文件中,我试图像这样模拟函数:

//conn.test.js
jest.mock('@upbs/nodejs-connection', () => ({
    mysql: {
        getConnection: jest.fn(() => ({
            select: jest.fn().mockReturnThis(),
            from: jest.fn().mockReturnThis(),
        }))
    }
}))

这似乎工作正常,但它会引发错误,因为我没有实现 .then.catch.finally

我尝试添加.then 的实现,但在调用mysql.getConnection 函数时出现超时。

我猜想添加 .then 实现会失败,因为它不是 mysql.getConnection 实际返回的 knex 函数的一部分

如何添加.then.catch.finally 的实现?

【问题讨论】:

    标签: javascript node.js amazon-web-services unit-testing jestjs


    【解决方案1】:

    以下模拟设置应该让您继续前进。对from 方法的调用需要返回一个具有then 方法的promise。无论 promise 的结果如何,都将调用 finally,因此还为 destroy 方法提供了一个模拟实现。

    mysql: {
      getConnection: jest.fn(() => ({
        select: jest.fn().mockReturnThis(),
        from: jest.fn().mockResolvedValueOnce({ col1: 10, col2: 20, col3: 30 }),
        destroy: jest.fn().mockReturnThis()
      }))
    }
    

    考虑重构您的代码以遵循单一职责原则,这将使编写测试更容易。

    【讨论】:

    • 这就像你写的那样工作,但它仍然使用真正的.then 实现。我尝试添加一个模拟实现,但它给了我之前看到的相同超时错误。这是我添加的模拟实现 `then: jest.fn((rows) => {console.log('using mock'); }),