NestJS RabbitMQ @golevelup/nestjs-rabbitmq 如何模拟服务调用来发布

问题描述 投票:0回答:1

我有一个使用 @golevelup/nestjs-rabbitmq 模块的有效 pub/sub 实现。

我想编写一个服务规范来测试 MessagingService 的发布方法,该方法调用 AmqpConnection 发布方法。如何在测试中模拟发布方法?

消息模块

import { RabbitModule } from '../rabbit/rabbit.module';
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { MessagingService } from './messaging.service';

@Module({
  imports: [
    RabbitModule,
    MessagingModule,
  ],
  providers: [ConfigService, MessagingService],
  controllers: [],
  exports: [MessagingService],
})
export class MessagingModule {}

消息服务

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
import { QueueMessage } from 'src/models/queue-message.model';
import { Logger } from '@nestjs/common';

@Injectable()
export class MessagingService {
  private readonly exchange: string = this.configService.get<string>('RABBITMQ_EXCHANGE') || 'drs-encrypt.exchange';
  private readonly routingKey: string = this.configService.get<string>('RABBITMQ_ROUTING_KEY') || 'drs-encrypt';
  private readonly logger = new Logger(MessagingService.name);

  constructor(
    private readonly configService: ConfigService,
    private readonly amqpConnection: AmqpConnection
  ) {}

  // Publish the queue message to the exchange
  public async publish<T>(queueMessage: QueueMessage): Promise<void> {
    this.logger.log(`publishing queueMessage to exchange: ${this.exchange} routing key: ${this.routingKey}`);
    await this.amqpConnection.publish(this.exchange, this.routingKey, queueMessage);
  }

}

消息服务 - 规范

import { Test, TestingModule } from '@nestjs/testing';
import { MessagingService } from '../messaging/messaging.service';
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq'
import { ConfigService } from '@nestjs/config';

describe('MessagingService', () => {
  let service: MessagingService;

  type MockType<T> = {
    [P in keyof T]?: jest.Mock<{}>;
  };

  const mockFactoryAmqpConnection: () => MockType<AmqpConnection> = jest.fn(() => ({
    publish: jest.fn(() => AmqpConnection),
  }));

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        ConfigService,
        MessagingService,
        {
          provide: AmqpConnection,
          useFactory: mockFactoryAmqpConnection,
        },
      ],
      controllers: [],
    }).compile();

    service = module.get<MessagingService>(MessagingService);

  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });  

});
testing jestjs rabbitmq nestjs
1个回答
0
投票

您在模块设置中所做的似乎是正确的,但由于您没有提供测试用例,因此很难知道出了什么问题。

但是,您可以尝试提供一个简单的对象作为模拟,而不是工厂,并使用它来检查是否使用正确的输入调用它:

   const amqpConnectionMock = { 
     publish: jest.fn()
   };
   const bindingMock = {
     exchange: 'test_exchange',
     routingKey: 'test_routing_key',
   }

   beforeEach(async () => {
    jest.clearAllMocks(); // start fresh
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        MessagingService,
        // you might want to mock the config too to provide a custom config for the test suite
        {
          provide: ConfigService,
          useValue: {
            get: () => bindingMock,
          },
        },
        {
          provide: AmqpConnection,
          useValue: amqpConnectionMock,
        },
      ],
      controllers: [],
    }).compile();

    service = module.get<MessagingService>(MessagingService);

  });

测试用例可能是这样的:

  it('should publish', async () => {
    const message: QueueMessage = { ... } // <- your message here
    
    await service.publish(message);
   
    expect(amqpConnectionMock.publish).toHaveBeenCalledWith(
      bindingMock.exchange,
      bindingMock.routingKey,
      message,
    );
  }); 

P.S:与问题没有直接关系,但您也可以考虑在服务中注入记录器。这将允许在测试模块中替换它,以避免不必要的消息污染您的测试日志。

© www.soinside.com 2019 - 2024. All rights reserved.