首页 > 解决方案 > 如何使用 sinon 存根 Winston 记录器

问题描述

我有一个使用 Winston NodeJs 包的记录器。记录器执行额外的逻辑,我希望进行单元测试以确保将正确的数据传递给 Winston。但是,由于我已经设置了外部传输(例如 Firehose),因此不需要调用它们。

我没有通过构造函数将 Winston 作为依赖项传递,但我尝试将createLogger方法、log方法和 Winston 作为一个整体进行存根,就像我通常在存根依赖项时所做的那样。

createStubbedInstance方法不适用于 Winston(或者,我无法使其工作),因为 Winston 不是作为类导出,而是作为命名空间导出。

import { Logger, ILoggerConfig } from './src';
import * as winston from 'winston'
describe('Logger', () => {
  let loggerConfig: ILoggerConfig;
  let sandbox: sinon.SinonSandbox;
  beforeEach(() => {
    sandbox = sinon.createSandbox();

    loggerConfig = {
      correlationId: faker.random.uuid(),
      action: 'GET',
    };
    sandbox = sinon.createSandbox();
    winstonStub = sandbox.stub(winston);
    winstonStub.createLogger.resolves();
    winstonStub.log.resolves();
    ...
  });

  it('should log with INFO log level', () => {
    const logger = new Logger(loggerConfig);
    logger.info('Hello there!');

    sinon.assert.calledOnce(winstonStub.log);
    sinon.assert.calledWith(winsonStub.log, sinon.match.has("level", 'info'))
  });
import { Logger, ILoggerConfig } from './src';
import * as winston from 'winston'
describe('Logger', () => {
  let loggerConfig: ILoggerConfig;
  let sandbox: sinon.SinonSandbox;
  beforeEach(() => {
    sandbox = sinon.createSandbox();

    loggerConfig = {
      correlationId: faker.random.uuid(),
      action: 'GET',
    };
    sandbox = sinon.createSandbox();
    winstonStub = sandbox.stub(winston, 'createLogger').resolves({ log: sanbox.stub() });
    ...
  });

  it('should log with INFO log level', () => {
    const logger = new Logger(loggerConfig);
    logger.info('Hello there!');

    sinon.assert.calledOnce(winstonStub);
  });

我希望能够断言存根将被调用一定次数。但是,存根的调用计数始终为 0,并且我收到一条错误消息,表明 Winston 由于权限问题而无法发布到 Firehose。我还设置了控制台传输,并且当我不应该看到控制台中的日志时。

标签: node.jssinonwinston

解决方案


由于项目的严格设置导致编译问题的连锁反应,我无法使用"esModuleInterop": truewith 。import winston from 'winston'

log幸运的是,当模拟直接失败时,我找到了一种干净的方法来模拟我需要的东西。

import * as tape from "tape";
import * as sinon from "sinon";
import * as winston from "winston";

tape('Stubbing winston', (test) => {
  test.test('Or at least part of it', (test) => {

    const logSpy = sinon.spy()

    sinon
      .stub(winston, "createLogger")
      .callsFake(() => ({
        log: logSpy,
      } as unknown as Logger));

    const logger = new MyLoggerThatUsesWinston()
    logger.log('Only lost');
    logger.log('four hours');
    logger.log('on this');

    test.equal(logSpy.callCount, 3, "")
    test.end();
  }
  test.end();
}

推荐阅读