如何使用玩笑模拟子第三方属性中的构造函数

时间:2019-01-22 13:30:39

标签: javascript node.js jestjs winston

我们有一个简单的快递应用程序。我们使用Winston作为第三方,以便能够正确处理日志记录。

const express = require('express');
const app = express();
const { createLogger, transports } = require('winston');

const port = process.env.PORT || 5000;
const logger = createLogger({ transports: [ new transports.Console()] });

const { catchAll } = require('./routes/catchall');

app.get('*', catchAll);

app.listen(port, () => logger.log({ level: 'info', message: `server listening on port ${port}!` }));

我们希望在单元测试中,检查是否已使用适当的参数调用了createLogger。

我们首先尝试仅使用jest.mock('winston),但开玩笑地抱怨TypeError: transports.Console is not a constructor

然后,我们尝试使用以下方法手动模拟软件包:

let { createLogger, transports } = require('winston');

const consoleClass = class Console{};
jest.doMock('winston', () => {
  return {
    createLogger: jest.fn(),
    transports: {
      Console: consoleClass
    }
  }
});

describe('logger', () => {
  it('should create proper logger', () => {
    expect(createLogger).lastCalledWith({ transports: [ new transports.Console()] })
  });
});

有关控制台的错误已消失。但是随后我们的测试失败了:

logger › should create proper logger

expect(jest.fn())[.not].lastCalledWith()

jest.fn() value must be a mock function or spy.
Received:
  function: [Function anonymous]

  39 | describe('logger', () => {
  40 |   it('should create proper logger', () => {
> 41 |     expect(createLogger).lastCalledWith({ transports: [ new transports.Console()] })
     |                          ^
  42 |   });
  43 | });
  44 |

  at Object.lastCalledWith (tests/app.spec.js:41:26)

我们尝试在doMock之后添加

createLogger.mockImplementation(() => {});

但它抱怨TypeError: createLogger.mockImplementation is not a function

我们如何同时替换运输属性和createLogger?

我们需要能够模拟createLogger的实现,然后才能在另一个测试中断言app.listen已经使用logger.log和适当的参数进行了调用。

1 个答案:

答案 0 :(得分:0)

尝试以下操作:

const mockCreateLogger = jest.fn().mockImplementation(() => {
  log: jest.fn()
});
const mockConsole = jest.fn().mockImplementation(() => () => {});
jest.mock('winston', () => ({
  createLogger: mockCreateLogger, // name must start with mock prefix
  transports: {
    Console: mockConsole // name must start with mock prefix
  }
}));

// here import the file you are testing after the mocks

describe('logger', () => {
  it('should create proper logger', () => {
    expect(mockCreateLogger).toHaveBeenCalledWith({ transports: expect.anything() })
  });
});

p.s。为了在此处正确编写单元测试,您还应该模拟express以便在模拟的app上工作,而不是导入“真实的”快递