如何模拟模块级实例

How to mock module level instance

我有这段代码需要测试

import Logger from './logger';

const logger = new Logger();

export function myFunction() {
  // do something
  logger.log('Hello');
}

如何测试函数 myFunction 是否调用了 logger.log?这是我尝试过但失败了

jest.mock('./logger');
const mockedLoggerClass = <jest.Mock>Logger;

describe('Test myFunction', () => {
  it('should call logger log', () => {
    const loggerInstance = {
       log: jest.fn()
    }

    mockedLoggerClass.mockReturnValue(() => loggerInstance);
    myFunction()
    expect(loggerInstance.log).toBeCalled; // Nope no call
  });

})

再试一次

const loggerInstance = {
   log: jest.fn()
}
jest.mock('./logger', () => {
  return function () {
    return loggerInstance;  // ReferenceError: Cannot access 'loggerInstance' before initialization
  }
});

describe('Test myFunction', () => {
  it('should call logger log', () => {
 
    myFunction()
    expect(loggerInstance.log).toBeCalled;
  });

})

我知道我们不应该将记录器初始化为全局范围但这不是我的代码所以我不能碰它。

您的 loggerInstance 和生产代码中的 logger 不是相同的引用。 logger 变量将在您导入 myFunction 后立即创建,然后您必须获取此 Logger 实例而不是尝试模拟另一个实例。

要做到这一点,您可以 get a mock instance by jest:

import { myFunction } from './index'; // a mocked logger already created
import Logger from './logger';

jest.mock('./logger'); // mock it

describe('myFunction', () => {
  let logger: jest.Mocked<Logger>;

  beforeEach(() => {
    logger = (Logger as jest.Mock).mock.instances[0]; // get the mocked instance
  });

  it('should call Logger.log function with "Hello"', () => {
    myFunction(); // action

    expect(logger.log).toBeCalledWith('Hello'); // expectation
  })
});

你在一个高组件(myFunction)中创建了一个依赖(logger),这是一种反依赖注入模式,这使得你的代码变得难以测试。您可以尝试模块模式,只是 export default new Logger() 而不是 export default class Logger...