简体   繁体   中英

How to mock a nest-winston logger dependency in nestjs unit tests

This question already exists , but it is marked as solved and the solution doesn't work at all for me.

I want to mock a nest-winston logger that is a dependency of a provider in 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();
    // ...
  }
}

The authors solution was to pass in the loggers token as a provider to the module with an empty useValue. I assume it is because they didn't want to actually call it, but just supply the dependency for one of the providers they 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();
});
});

However, when trying to run the tests, it tries to find this.logger.log and when this.logger returns as {} it says this.logger.log is not a function . Does anyone know of a way to properly mock the logger dependency and can help me with this? The auto mocking described in nestjs documentation did not work for me either.

I am very new with jest and nestjs, and my plaster solution thusfar is to replace the empty useValue with

{
  log: jest.fn(),
  debug: jest.fn(),
  info: jest.fn(),
  warn: jest.fn(),
  error: jest.fn(),
}

, which is just... awful. Help will be greatly appreciated!

First off, I would suggest not setting every provider and then using override provider. Instead, use a simple custom provider like

{
  provide: StripeService,
  useValue: mockStripeService
}

Much less boilerplate when you have this many services. I keep the override*() methods for my integration and e2e tests where I need to override a provider that is registered by another module.

Second, if all you end up using in your method is this.logger.log then mockign log to jest.fn() is a fine approach.

{
  provide: WINSTON_NEST_MODULE_PROVIDER,
  useValue: { log: jest.fn() }
}

That will allow your code to run and nothing to log out to the console from the logger.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM