unit-testing - 如何模拟对 logger.warn 的调用?

标签 unit-testing jestjs log4js-node

我正在练习测试先行的开发,我想确保类中的方法总是在 warn 级别调用我的记录器并显示一条消息。我的类(class)定义如下:

import { log4js } from '../config/log4js-config'

export const logger = log4js.getLogger('myClass')

class MyClass {
  sum(numbers) {
    const reducer = (accumulator, currentValue) => accumulator + currentValue
    const retval = numbers.reduce(reducer))
    if (retval < 0) {
      logger.warn('The sum is less than zero!')
    }
    return retval
  }
}

const myClass = new MyClass()
export { myClass }

我的测试是这样的:

import { myClass, logger } from './MyClass'
import { log4js } from '../config/log4js-config'

jest.mock('log4js')

describe('MyClass', () => {

  it('logs a warn-level message if sum is negative', () => {
    logger.warn = jest.fn()
    logger._log = jest.fn()
    myClass.sum([0, -1])
    expect(logger.warn).toHaveBeenCalled() // <--- fails
    expect(logger._log).toHaveBeenCalled() // <--- fails
  })
})

我还尝试在设置中模拟 log4js.Logger._log 但这似乎也不起作用。 😕 欢迎提出任何建议!

最佳答案

模拟的事情是你需要提供模拟,对我来说最简单的方法是通过 mock factory .但是我也会推荐一些重构:

import { getLogger } from 'log4js'

export const logger = getLogger('myClass')
logger.level = 'debug'

// export the class itself to avoid memory leaks
export class MyClass {
  // would consider even export just the sum function
  sum(numbers) {
    const reducer = (accumulator, currentValue) => accumulator + currentValue
    const retval = numbers.reduce(reducer))
    if (retval < 0) {
      logger.warn('The sum is less than zero!')
    }
    return retval
  }
}

import log4js from 'log4js';
import { MyClass } from "./class";

jest.mock('log4js', () => {
    // using the mock factory we mimic the library.

    // this mock function is outside the mockImplementation 
    // because we want to check the same mock in every test,
    // not create a new one mock every log4js.getLogger()
    const warn = jest.fn()
    return {
        getLogger: jest.fn().mockImplementation(() => ({
            level: jest.fn(),
            warn,
        })),
    }
})

beforeEach(() => {
    // reset modules to avoid leaky scenarios
    jest.resetModules()
})

// this is just some good habits, if we rename the module
describe(MyClass, () => {

    it('logs a warn-level message if sum is negative', () => {
        const myClass = new MyClass()
        myClass.sum([0, -1])

        // now we can check the mocks
        expect(log4js.getLogger).toHaveBeenCalledTimes(1) // <--- passes
        // check exactly the number of calls to be extra sure
        expect(log4js.getLogger().warn).toHaveBeenCalledTimes(1) // <--- passes
    })

})

关于unit-testing - 如何模拟对 logger.warn 的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57275304/

相关文章:

python - 如何在测试中导入被测试的模块?

java - 单元测试 JAX-RS Controller 的最佳方法?

javascript - 如何在 Jest 中的异步函数中抛出错误

jestjs - 开 Jest 异步测试 - expect.assertion 似乎是全局性的

javascript - 我在使用 Node js 在 debian 中运行 js 脚本时遇到问题

javascript - log4js 库是异步的吗?

android - Robolectric 测试在 Android Studio 中运行但不在命令行中运行

unit-testing - 可以使用 mockito 模拟抽象类吗?

reactjs - 使用 Jest/Enzyme 的 FlatList 测试

javascript - Nodejs 中的 log4js-node 未记录到文件