【问题标题】:How to mock a call to logger.warn?如何模拟对 logger.warn 的调用?
【发布时间】:2019-12-08 01:27:38
【问题描述】:

我正在练习测试优先开发,我想确保类中的方法始终在 warn 级别调用我的记录器并显示消息。我的班级是这样定义的:

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,但这似乎也不起作用。 ???任何建议表示赞赏!

【问题讨论】:

  • 您似乎只是停止输入您的问题,因为测试中没有示例。要获得您的问题的答案,最好展示您的尝试,然后让社区帮助纠正您遇到的错误,而不是让社区告诉您如何去做。请参阅stackoverflow.com/help/mcve,了解如何编写一个有可能得到回答的好问题。
  • 对不起,网站滞后,我很惊讶发布了这么多。会更新。
  • 我认为您需要在加载真实类之前创建模拟。
  • Jest 将 jest.mock() 提升到套件的顶部,以便在加载导入之前模拟 log4js。你能把你的建议作为答案吗?
  • 能把'../config/log4js-config'的内容加进去吗?

标签: unit-testing jestjs log4js-node


【解决方案1】:

模拟的问题是你需要提供模拟,对我来说最简单的方法是通过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
    })

})

【讨论】:

    【解决方案2】:

    也许简单地监视记录器方法就可以解决问题

    import { myClass, logger } from './MyClass'
    
    describe('MyClass', () => {
    
      it('logs a warn-level message if sum is negative', () => {
        const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {});
        const _logSpy = jest.spyOn(logger, '_log').mockImplementation(() => {});
        myClass.sum([0, -1])
        expect(warnSpy).toHaveBeenCalled()
        expect(_logSpy).toHaveBeenCalled()
      })
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-04
      相关资源
      最近更新 更多