如何在 Service 构造函数中对 Controller 进行单元测试和模拟 @InjectModel

Posted

技术标签:

【中文标题】如何在 Service 构造函数中对 Controller 进行单元测试和模拟 @InjectModel【英文标题】:How to unit test Controller and mock @InjectModel in the Service constructor 【发布时间】:2019-03-23 12:01:28 【问题描述】:

我在对我的控制器进行单元测试时遇到问题并收到错误消息“Nest 无法解析我的服务的依赖项”。

为了获得最大的覆盖率,我想对控制器和相应的服务进行单元测试,并想模拟像猫鼬连接这样的外部依赖项。同样,我已经尝试过以下链接中提到的建议,但没有找到任何运气:

https://github.com/nestjs/nest/issues/194#issuecomment-342219043

请在下面找到我的代码:

export const deviceProviders = [
    
        provide: 'devices',
        useFactory: (connection: Connection) => connection.model('devices', DeviceSchema),
        inject: ['DbConnectionToken'],
    ,
];


export class DeviceService extends BaseService 
    constructor(@InjectModel('devices') private readonly _deviceModel: Model<Device>) 
        super();
    

    async getDevices(group): Promise<any> 
        try 
            return await this._deviceModel.find( Group: group ).exec();
         catch (error) 
            return Promise.reject(error);
        
    



@Controller()
export class DeviceController 
    constructor(private readonly deviceService: DeviceService) 
    

   @Get(':group')
   async getDevices(@Res() response, @Param('group') group): Promise<any> 
        try 
            const result = await this.deviceService.getDevices(group);
            return response.send(result);
        
        catch (err) 
            return response.status(422).send(err);
        
    



@Module(
    imports: [MongooseModule.forFeature([ name: 'devices', schema: DeviceSchema ])],
    controllers: [DeviceController],
    components: [DeviceService, ...deviceProviders],
)
export class DeviceModule  

单元测试:

describe('DeviceController', () => 
    let deviceController: DeviceController;
    let deviceService: DeviceService;

    const response = 
        send: (body?: any) =>  ,
        status: (code: number) => response,
    ;

    beforeEach(async () => 
        const module = await Test.createTestingModule(
            controllers: [DeviceController],
            components: [DeviceService, ...deviceProviders],
        ).compile();

        deviceService = module.get<DeviceService>(DeviceService);
        deviceController = module.get<DeviceController>(DeviceController);
    );

    describe('getDevices()', () => 
        it('should return an array of devices', async () => 
            const result = [
                Group: 'group_abc',
                DeviceId: 'device_abc',
            ,
            
                Group: 'group_xyz',
                DeviceId: 'device_xyz',
            ];
            jest.spyOn(deviceService, 'getDevices').mockImplementation(() => result);

            expect(await deviceController.getDevices(response, null)).toBe(result);
        );
    );
);

当我在上面运行我的测试用例时,我遇到了两个错误:

Nest 无法解析 DeviceService (?) 的依赖关系。请确保索引 [0] 处的参数在当前上下文中可用。

无法窥探原始值;给定的未定义

【问题讨论】:

【参考方案1】:

您没有在此处注入正确的令牌。您必须使用函数getModelToken 而不是纯字符串。

import  getModelToken  from '@nestjs/mongoose';

// ...

 provide: getModelToken('devices'), useFactory: myFactory ,

【讨论】:

【参考方案2】:

示例代码:

import  Test  from '@nestjs/testing';

import  getModelToken  from '@nestjs/mongoose';


describe('auth', () => 
  let deviceController: DeviceController;
  let deviceService: DeviceService;

  const mockRepository = 
    find() 
      return ;
    
  ;

  beforeAll(async () => 
    const module = await Test.createTestingModule(
      imports: [DeviceModule]
    )
      .overrideProvider(getModelToken('Auth'))
      .useValue(mockRepository)
      .compile();

    deviceService = module.get<DeviceService>(DeviceService);
  );

  // ...


);

【讨论】:

以上是关于如何在 Service 构造函数中对 Controller 进行单元测试和模拟 @InjectModel的主要内容,如果未能解决你的问题,请参考以下文章

如何在Node.js中对使用promises和事件发射器的函数进行单元测试?

在 service.subscribe 中组件的构造函数中的 Angular 更新不起作用

使用构造函数注入的弹簧@RestController中的空异常@Service

多次调用Angular Service单例构造函数

如何在Java中对MongoDB按日期进行查询统计

Service 应该定义怎样的方法?