typescript - วิธีการจำลองการขึ้นต่อของ logger nest-winston ในการทดสอบหน่วยของ nestjs
คำถามนี้มีอยู่แล้ว แต่ถูกทำเครื่องหมายว่าสำเร็จแล้ว และวิธีแก้ปัญหาไม่ได้ผลสำหรับฉันเลย
ฉันต้องการจำลอง logger ของ nest-winston ที่เป็น dependency ของ provider ใน nestjs
@Controller('builder/instance')
export class InstanceController {
private executor: Executor;
constructor(
@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: Logger,
private stripeService: StripeService,
private instanceService: InstanceService,
private organizationService: OrganizationService,
private executorFactory: ExecutorFactory,
private socketService: SocketService,
private auditLogService: AuditLogService,
) {
this.logger.log("hello world!", InstanceController.name);
this.executor = this.executorFactory.getExecutor();
// ...
}
}
วิธีแก้ของผู้เขียนคือการส่งโทเค็นของ logger เป็น provider ให้กับโมดูลโดยใช้ useValue ว่าง ฉันคิดว่านั่นเป็นเพราะพวกเขาไม่ต้องการเรียกใช้งานจริง ๆ แต่เพียงแค่จัดหาการพึ่งพาสำหรับหนึ่งใน provider ที่พวกเขา mock
describe('InstanceController', () => {
let controller: InstanceController;
const mockStripeService = {};
const mockInstanceService = {};
const mockOrganizationService = {};
const mockExecutorFactory = {};
const mockSocketService = {};
const mockAuditLogService = {};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
// imports: [AccountModule],
controllers: [InstanceController],
providers: [
{ provide: WINSTON_NEST_MODULE_PROVIDER, useValue: {} },
StripeService,
InstanceService,
OrganizationService,
ExecutorFactory,
SocketService,
AuditLogService,
],
})
.overrideProvider(StripeService)
.useValue(mockStripeService)
.overrideProvider(InstanceService)
.useValue(mockInstanceService)
.overrideProvider(OrganizationService)
.useValue(mockOrganizationService)
.overrideProvider(ExecutorFactory)
.useValue(mockExecutorFactory)
.overrideProvider(SocketService)
.useValue(mockSocketService)
.overrideProvider(AuditLogService)
.useValue(mockAuditLogService)
.compile();
controller = module.get<InstanceController>(InstanceController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
อย่างไรก็ตาม เมื่อพยายามรันการทดสอบ มันพยายามหาฟังก์ชัน this.logger.log และเมื่อ this.logger คืนค่าเป็น {} มันจะบอกว่า this.logger.log is not a function มีใครรู้วิธี จำลอง dependency ของ logger อย่างถูกต้องและช่วยฉันเรื่องนี้ได้ไหม? การจำลองอัตโนมัติที่อธิบายไว้ในเอกสารของ NestJS ก็ไม่ทำงานสำหรับฉันเช่นกัน.
ฉันยังใหม่มากกับ jest และ nestjs และวิธีแก้ของฉันจนถึงตอนนี้คือการแทนที่ useValue ที่ว่างด้วย
{
log: jest.fn(),
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
}
, ซึ่งมันแย่มาก ความช่วยเหลือจะได้รับการขอบคุณอย่างสูง!
คำตอบ #1
อันดับแรก ฉันขอแนะนำว่าอย่าตั้งค่า provider ทุกตัวแล้วค่อยใช้ override provider แทน ให้ใช้ provider แบบกำหนดเองง่าย ๆ เช่น
{
provide: StripeService,
useValue: mockStripeService
}
โค้ดซ้ำซ้อนน้อยลงมากเมื่อคุณมีบริการมากขนาดนี้ ฉันเก็บเมธอด override*() ไว้สำหรับการทดสอบการรวมระบบและการทดสอบ e2e ของฉันในกรณีที่ฉันจำเป็นต้อง override provider ที่ถูกลงทะเบียนโดยโมดูลอื่น
ประการที่สอง ถ้าสิ่งเดียวที่คุณใช้ในวิธีของคุณคือ this.logger.log ดังนั้นการทำ mock log ให้เป็น jest.fn() ก็เป็นวิธีที่ใช้ได้
{
provide: WINSTON_NEST_MODULE_PROVIDER,
useValue: { log: jest.fn() }
}
นั่นจะช่วยให้โค้ดของคุณสามารถรันได้และไม่มีอะไรถูกบันทึกออกไปที่คอนโซลจากตัวบันทึก
คำตอบ #2
เพิ่มเติมสักหน่อย: ถ้าใครใช้ @golevelup/ts-jest คุณสามารถสร้าง Mock ให้กับ LoggingService ทั้งหมดได้ ดังนั้นคุณไม่จำเป็นต้องเพิ่ม jest.fn() สำหรับแต่ละเมธอดที่คุณอาจใช้ในคลาสที่กำลังทดสอบ:
import { createMock } from '@golevelup/ts-jest';
import { LoggerService } from '@nestjs/common';
...
{
provide: WINSTON_MODULE_NEST_PROVIDER,
useValue: createMock<LoggerService>(),
}
