gpt4 book ai didi

typescript - 如何使用 Jest 模拟封装在服务类中的 winston 记录器实例

转载 作者:行者123 更新时间:2023-12-04 00:02:32 24 4
gpt4 key购买 nike

我试图模拟一个封装在用 NestJS 创建的服务类中的 winston.Logger 实例。我在下面包含了我的代码。

我无法从服务类中触发模拟的记录器实例。谁能解释我哪里出错了?

import * as winston from 'winston';

import { loggerOptions } from '../logger/logger.config';
import { LoggingService } from '../logger/logger.service';

const logger: winston.Logger = winston.createLogger(loggerOptions);

// trying to mock createLogger to return a specific logger instance
const winstonMock = jest.mock('winston', () => (
{
format: {
colorize: jest.fn(),
combine: jest.fn(),
label: jest.fn(),
timestamp: jest.fn(),
printf: jest.fn()
},
createLogger: jest.fn().mockReturnValue(logger),
transports: {
Console: jest.fn()
}
})
);


describe("-- Logging Service --", () => {
let loggerMock: winston.Logger;

test('testing logger log function called...', () => {
const mockCreateLogger = jest.spyOn(winston, 'createLogger');
const loggingService: LoggingService = LoggingService.Instance;
loggerMock = mockCreateLogger.mock.instances[0];
expect(loggingService).toBeInstanceOf(LoggingService)
expect(loggingService).toBeDefined();
expect(mockCreateLogger).toHaveBeenCalled()

// spy on the winston.Logger instance within this test and check
// that it is called - this is working from within the test method
const logDebugMock = jest.spyOn(loggerMock, 'log');
loggerMock.log('debug','test log debug');
expect(logDebugMock).toHaveBeenCalled();

// now try and invoke the logger instance indirectly through the service class
// check that loggerMock is called a second time - this fails, only called once
// from the preceding lines in this test
loggingService.debug('debug message');
expect(logDebugMock).toHaveBeenCalledTimes(2);
});

...

LoggingService调试方法代码
public debug(message: string) {
this.logger.log(
{
level: types.LogLevel.DEBUG,
message: message,
meta: {
context: this.contextName
}
}
);
}

更新:2019 年 3 月 9 日

将我的nestjs LoggingService 重构为在构造函数中依赖注入(inject)winston 记录器实例,以方便单元测试。这使我能够在 winston 记录器的 log 方法上使用 jest.spyOn 并检查它是否已在服务实例中被调用:

// create winstonLoggerInstance here, e.g. in beforeEach()....
const winstonLoggerMock = jest.spyOn(winstonLoggerInstance, 'log');
serviceInstance.debug('debug sent from test');
expect(winstonLoggerMock).toHaveBeenCalled();

最佳答案

我已经测试了您的代码,似乎 jest.mock 的使用存在多个问题。

为了正确地模拟一个模块,你必须先模拟它,然后再导入它。这是一种内部机制(jest 如何模拟模块),您必须遵循此规则。

const logger = {
debug: jest.fn(),
log: jest.fn()
};

// IMPORTANT First mock winston
jest.mock("winston", () => ({
format: {
colorize: jest.fn(),
combine: jest.fn(),
label: jest.fn(),
timestamp: jest.fn(),
printf: jest.fn()
},
createLogger: jest.fn().mockReturnValue(logger),
transports: {
Console: jest.fn()
}
}));

// IMPORTANT import the mock after
import * as winston from "winston";
// IMPORTANT import your service (which imports winston as well)
import { LoggingService } from "../logger/logger.service";


如您所见,您不能使用 winston 实例作为模拟的返回值,但不用担心,也可以模拟该实例。 (您也可以在前面的代码示例中看到它)
const logger = {
debug: jest.fn(),
log: jest.fn()
};

最后,你不需要窥探你曾经 mock 过的东西,所以直接问 mock 就行了。

完整的代码在这里:
const logger = {
debug: jest.fn(),
log: jest.fn()
};

// trying to mock createLogger to return a specific logger instance
jest.mock("winston", () => ({
format: {
colorize: jest.fn(),
combine: jest.fn(),
label: jest.fn(),
timestamp: jest.fn(),
printf: jest.fn()
},
createLogger: jest.fn().mockReturnValue(logger),
transports: {
Console: jest.fn()
}
}));

import * as winston from "winston";
import { LoggingService } from "./logger.service";

describe("-- Logging Service --", () => {
let loggerMock: winston.Logger;

test("testing logger log function called...", () => {
const mockCreateLogger = jest.spyOn(winston, "createLogger");
const loggingService: LoggingService = LoggingService.Instance;
loggerMock = mockCreateLogger.mock.instances[0];
expect(loggingService).toBeInstanceOf(LoggingService);
expect(loggingService).toBeDefined();
expect(mockCreateLogger).toHaveBeenCalled();

// spy on the winston.Logger instance within this test and check
// that it is called - this is working from within the test method
logger.log("debug", "test log debug");
expect(logger.log).toHaveBeenCalled();

// now try and invoke the logger instance indirectly through the service class
// check that loggerMock is called a second time - this fails, only called once
// from the preceding lines in this test
loggingService.debug("debug message");

expect(logger.debug).toHaveBeenCalledTimes(1); // <- here
});
});

我将最后的断言改为了一个,因为我调用了 log在测试中,和 debug在 LoggingService 中。

这是我使用的记录器服务:
import * as winston from "winston";

export class LoggingService {
logger: winston.Logger;

static get Instance() {
return new LoggingService();
}

constructor() {
this.logger = winston.createLogger();
}

debug(message: string) {
this.logger.debug(message);
}
}

玩得开心!

关于typescript - 如何使用 Jest 模拟封装在服务类中的 winston 记录器实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57771616/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com