ค้นหาเว็บไซต์

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

บทความที่เกี่ยวข้อง