nestjs 单元测试 createTestingModule 依赖注入

Posted

技术标签:

【中文标题】nestjs 单元测试 createTestingModule 依赖注入【英文标题】:nestjs unit test createTestingModule Dependency Injection 【发布时间】:2021-05-29 06:01:46 【问题描述】:

我希望你能帮助我。 我正在使用带有最新 angular/nestjs 的 Nx(日期:2 月 26 日)

    ...
    "@nestjs/common": "^7.0.0",
    "@nestjs/config": "^0.6.3",
    "@nestjs/core": "^7.0.0",
    "@nestjs/platform-express": "^7.0.0",
    "@nestjs/platform-socket.io": "^7.6.7",
    "@nestjs/websockets": "^7.6.7",
    "jest": "26.2.2",
    "@nrwl/jest": "11.4.0",
    ...

我无法使用带有 Jest 的 NestJS 运行我的单元测试 我想测试以下服务:

@Injectable()
export class CoreApiService 
  logger = new Logger('CoreApiService');
  apiEndpoint;

  constructor(private httpService: HttpService, configService: ConfigService) 
    this.apiEndpoint = configService.get('API_SERVICE_ENDPOINT');
  

我收到以下错误:

TypeError: Cannot read property 'get' of undefined

所以看来 ConfigService(以及 httpService)总是未定义的。

当记录 httpService 和 ConfigService 时,它​​总是未定义的。 即使我尝试实例化像new CoreApiService(new HttpService(), new ConfigService()) 这样的新实例 我什至在测试本身中尝试过 new CoreApiService( as any, get: (...params => return 'foo') 之类的东西

总是会出现上述相同的错误。

测试文件:

import  Test, TestingModule  from '@nestjs/testing';
import  CoreApiService  from './core-api.service';
import  ConfigModule, ConfigService  from '@nestjs/config';
import  HttpModule  from '@nestjs/common';


class ConfigServiceMock 
  get(key: string): string 
    switch (key) 
      case 'API_SERVICE_ENDPOINT':
        return '';
    
  


describe('CoreApiService', () => 
  let module: TestingModule;
  let service: CoreApiService;

  beforeEach(async () => 
    module = await Test.createTestingModule(
      imports: [HttpModule, ConfigModule],
      providers: [
        CoreApiService,
         provide: ConfigService, useClass: ConfigServiceMock ,
      ],
    ).compile();
    service = module.get<CoreApiService>(CoreApiService);
  );

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


我什至试过:.overrideProvider(ConfigService).useClass(ConfigServiceMock)

提前谢谢你!

编辑 03/01

似乎模块本身的编译步骤失败了... 所以对于当前的测试文件,日志“COMPILED”将永远不会被执行。

 CoreApiService › should be defined

    TypeError: Cannot read property 'get' of undefined

      22 |
      23 |   constructor(private httpService: HttpService, configService: ConfigService) 
    > 24 |     this.apiEndpoint = configService.get('API_SERVICE_ENDPOINT');
         |                                      ^
      25 |   
      26 |
      27 |   private static createRequestConfig(options: RequestHeader): RequestConfig 

      at new CoreApiService (src/app/core-api/core-api.service.ts:24:38)
      at Injector.instantiateClass (../../node_modules/@nestjs/core/injector/injector.js:286:19)
      at callback (../../node_modules/@nestjs/core/injector/injector.js:42:41)
      at Injector.resolveConstructorParams (../../node_modules/@nestjs/core/injector/injector.js:114:24)
      at Injector.loadInstance (../../node_modules/@nestjs/core/injector/injector.js:46:9)
      at Injector.loadProvider (../../node_modules/@nestjs/core/injector/injector.js:68:9)
          at async Promise.all (index 5)
      at InstanceLoader.createInstancesOfProviders (../../node_modules/@nestjs/core/injector/instance-loader.js:43:9)
      at ../../node_modules/@nestjs/core/injector/instance-loader.js:28:13
          at async Promise.all (index 1)
      at InstanceLoader.createInstances (../../node_modules/@nestjs/core/injector/instance-loader.js:27:9)
      at InstanceLoader.createInstancesOfDependencies (../../node_modules/@nestjs/core/injector/instance-loader.js:17:9)
      at TestingModuleBuilder.compile (../../node_modules/@nestjs/testing/testing-module.builder.js:43:9)

  ● CoreApiService › should be defined

    expect(received).toBeDefined()

    Received: undefined

      44 |   it('should be defined', () => 
      45 |     console.log('SHOULD BE DEFINED')
    > 46 |     expect(service).toBeDefined();
         |                     ^
      47 |   );
      48 | );
      49 |

      at Object.<anonymous> (src/app/core-api/core-api.service.spec.ts:46:21)

当前测试文件如下:

import  Test, TestingModule  from '@nestjs/testing';
import  CoreApiService  from './core-api.service';
import  ConfigService  from '@nestjs/config';
import  HttpService, INestApplication  from '@nestjs/common';

class ConfigServiceMock 
  get(key: string): string 
    switch (key) 
      case 'API_SERVICE_ENDPOINT':
        return '';
    
  


class HttpServiceMock 
  get(): any 

  


describe('CoreApiService', () => 
  let module: TestingModule;
  let service: CoreApiService;
  let app: INestApplication;

  beforeEach(async () => 
    console.log('beforeEach')
    module = await Test.createTestingModule(
      imports: [],
      providers: [
         provide: ConfigService, useClass: ConfigServiceMock ,
         provide: HttpService, useClass: HttpServiceMock ,
        CoreApiService,
      ],
    )
      .compile();
    console.log('COMPILED');
    app = module.createNestApplication();
    await app.init();
    service = module.get<CoreApiService>(CoreApiService);
  );

  it('should be defined', () => 
    console.log('SHOULD BE DEFINED')
    expect(service).toBeDefined();
  );
);

我也玩过提供者部分的顺序,但我想这无关紧要......

【问题讨论】:

删除ConfigModule,但通常您的模拟和测试设置看起来不错。我也会嘲笑HttpService,但它应该可以工作 您可以使用useValue 而不是useClass 代替ConfigServiceMock,然后使用地图。这样你就不需要模拟 get 函数。 (例如:const ConfigServiceMock = new Map([['foo', 'bar']]); 【参考方案1】:

您可能想尝试的两件事:

    初始化您的 Nest 应用程序。在beforeEach 中,在您的模块中调用compile() 之后,添加以下行:
app = module.createNestApplication();
await app.init();
    不要在您的测试中导入ConfigModule。这将初始化实际的配置服务,你在模拟它时不需要它。

【讨论】:

感谢您的建议。我已经尝试删除 ConfigModule 并完成了这个测试,但没有成功 即使使用创建嵌套应用程序和编译后的等待,测试也会因以下错误而中断:```TypeError: Cannot read property 'get' of undefined 所以配置服务仍然未定义跨度>

以上是关于nestjs 单元测试 createTestingModule 依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

使用注入对 NestJS 控制器进行单元测试

使用 NestJS 服务单元测试未找到连接“默认”

在 NestJS 中使用 Jest 和 MongoDB 进行单元测试

服务的 NestJS 单元测试:模拟 getManager 导致“未找到连接“默认””错误

如何对 NestJS 中的控制器应用警卫进行单元测试?

使用请求对 NestJS 控制器进行单元测试