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



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

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的实现,然后能够在另一个测试中断言app.listen已被使用记录器.log和适当的参数调用。

尝试以下方法:

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() })
  });
});

附言为了在这里正确编写单元测试,您还应该模拟express以便处理模拟app而不是导入"真实"的表达式

最新更新