NestJS - gRPC 客户端 E2E 测试

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

我正在尝试为具有 gRPC 客户端的 NestJS 微服务编写 e2e 测试。无论我如何尝试在 e2e 测试中模拟 ClientsModule,它似乎仍然无法获取配置并且无法找到 *.proto 文件。

请在下面找到我的代码示例:

app.module.ts 中的客户端模块

// src/app.module.ts
@Module({
 imports: [
   HttpModule,
   ...
   ...
   ClientsModule.register([
     {
       name: 'USERS_PACKAGE',
       transport: Transport.GRPC,
       options: {
         package: 'users',
         credentials: credentials.createInsecure(),
         protoPath: join(__dirname, '../proto/users.proto'),
         url: 'users-grpc-server.users:50051',
      },
    },
  ]),
 ],
controllers: [UsersController],
providers: [UsersService, UsersClient],
})
export class AppModule {}

用户客户端对 gRPC Server NestJS 微服务进行 gRPC 调用:

// src/clients/users.client.ts

@Injectable()
export class UsersClient implements OnModuleInit {
  private readonly logger: Logger = new Logger(UsersClient.name);
  private readonly API_KEY: string = this.configService.get<string>('services.v1.api-key');

  private usersController: usersController;

  constructor(@Inject('USERS_PACKAGE') private client: ClientGrpc, private configService: ConfigService) {}

  onModuleInit() {
    this.usersController = this.client.getService<UsersController>('UsersController');
  }

  async getUsers(headers: IncomingHttpHeaders, userId: string): Promise<Users> {
  
    let users: Users = null;

    const metadata = new Metadata();
    metadata.add('Authorization', headers.authorization);
    metadata.add('x-api-key', this.API_KEY);

    try {
      users = await this.usersController.getUsers({}, metadata);
    } catch (e) {
      const { message, response: { status = 500 } = {}, stack } = e;
      this.logger.error(stack);
      throw new HttpException(message, status);
    }

    return users;
  }
}

更新nest-cli.json

{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [{"include": "../config/*.yaml", "outDir": "./dist/config"}, {"include": "**/*.proto", "outDir": "./dist"}]
  }
}

e2e测试配置

 // test/app.e2e-spec.json

  let app: NestFastifyApplication;
  let httpService: HttpService;
  let cacheManager: Cache;

  beforeAll(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        HttpModule,
        ...
        ...
        ClientsModule,
      ],
    })
      .overrideProvider(ClientsModule)
      .useValue({
        name: 'USERS_PACKAGE',
        transport: Transport.GRPC,
        options: {
          package: 'users',
          credentials: ServerCredentials.createInsecure(),
          protoPath: join(__dirname, '../src/proto/users.proto'),
          url: 'localhost:50051',
        },
      })
      .compile();

    app = module.createNestApplication(new FastifyAdapter());

    await app.init();
    await app.getHttpAdapter().getInstance().ready();

    httpService = module.get<HttpService>(HttpService);
    cacheManager = module.get<Cache>(CACHE_MANAGER);
});

错误:

  ● Test suite failed to run

    The invalid .proto definition (file at "/users-service-grpc-client/app/proto/users.proto" not found)

    > 26 |     ClientsModule.register([
         |                   ^
      27 |       {
      28 |         name: 'USERS_PACKAGE',
      29 |         transport: Transport.GRPC,

      at ClientGrpcProxy.loadProto (node_modules/@nestjs/microservices/client/client-grpc.js:220:39)
      at ClientGrpcProxy.createClients (node_modules/@nestjs/microservices/client/client-grpc.js:193:34)
      at new ClientGrpcProxy (node_modules/@nestjs/microservices/client/client-grpc.js:29:33)
      at Function.create (node_modules/@nestjs/microservices/client/client-proxy-factory.js:27:24)
      at node_modules/@nestjs/microservices/module/clients.module.js:12:80
          at Array.map (<anonymous>)
      at Function.register (node_modules/@nestjs/microservices/module/clients.module.js:10:41)
      at Object.<anonymous> (src/app.module.ts:26:19)

看起来 e2e 测试没有使用测试中的

ClientsModule
配置,并且仍在使用
app.module.ts
中的 ClientsModule 配置。

有谁知道正确配置的方法吗?

nestjs grpc grpc-node nestjs-config nestjs-testing
2个回答
1
投票

我不确定这是如何工作的,但我将 src/app.module.ts 中的 ClientsModule 更改为 registerAsync,因为我想让 url 动态化,现在它似乎工作正常

// src/app.module.ts
@Module({
 imports: [
   HttpModule,
   ...
   ...
   ClientsModule.registerAsync([
    {
      name: 'USERS_PACKAGE',
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        transport: Transport.GRPC,
        options: {
          package: 'users',
          credentials: credentials.createInsecure(),
          protoPath: join(__dirname, '../proto/users.proto'),
          url: configService.get<string>('services.users-grpc-server-service.url'),
        },
      }),
      inject: [ConfigService],
    },
  ]),
 ],
controllers: [UsersController],
providers: [UsersService, UsersClient],
})
export class AppModule {}

注意:在E2E测试中,我还必须使用overrideProvider来模拟grpc调用

// test/app.e2e-spec.ts

const module: TestingModule = await Test.createTestingModule({
      imports: [
        HttpModule,
        ...
        ...
        ClientsModule,
      ],
    })
      .overrideProvider('USERS_PACKAGE')
      .useValue({
        getService: () => ({
          getUsers: jest.fn().mockReturnValue({
            "name": "test user",
            "age": "55",
            "height": "1.89"
          }),
        }),
      })
      .compile();


0
投票

就我而言,我必须这样做

import { join } from 'path';
import { Env, NODE_ENV } from '@backend/utilities';

export const AUTH_SERVICE_PROTO_PATH =
  NODE_ENV === Env.E2E
    ? 'apps/backend/users/src/proto/auth.proto'
    : join(__dirname, 'proto/auth.proto');

因此,对于 e2e 测试,我们使用静态路径。

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