You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS E2E测试覆盖Provider时依赖注入失效问题排查

问题:NestJS E2E测试中依赖注入失效,控制器内CatsService为undefined

错误日志

stdout | src/resources/cats/cat.spec.ts > Cats
beforeAll

stdout | src/resources/cats/cat.spec.ts > Cats
app initialized

stdout | src/resources/cats/cat.spec.ts > Cats > /GET cats
catsService undefined

[Nest] 34132  - 09/29/2025, 5:41:37 PM   ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'findOne')
TypeError: Cannot read properties of undefined (reading 'findOne')
    at CatsController.findOne (/Users/user/code/dvmonorepo/apps/backend/src/resources/cats/cat.controller.ts:16:29)

相关代码

CatsModule

import { Module } from '@nestjs/common';
import { CatsService } from './cat.service';
import { CatsController } from './cat.controller';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService],
})
export class CatsModule {}

CatsController

import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cat.service';

@Controller('cats')
export class CatsController {
  constructor(
    private readonly catsService: CatsService,
  ) {}

  @Get(':catId')
  findOne() {
    console.log('catsService', this.catsService);
    return this.catsService.findOne('1');
  }
}

CatsService

import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {
  constructor() {}

  async findOne(id: string) {
    return { id, email: 'cat@test.com', name: 'Test Cat' }
  }
}

测试代码

import request from 'supertest';
import { Test } from '@nestjs/testing';
import { CatsModule } from './cat.module';
import { CatsService } from './cat.service';
import { INestApplication } from '@nestjs/common';

describe('Cats', () => {
  let app: INestApplication;
  let catsService = { findOne: () => ['test'] };

  beforeAll(async () => {
    console.log('beforeAll');
    const moduleRef = await Test.createTestingModule({
      imports: [CatsModule],
    })
      .overrideProvider(CatsService)
      .useValue(catsService)
      .compile();

    app = moduleRef.createNestApplication();
    await app.init();
    console.log('app initialized');
  });

  it(`/GET cats`, () => {
    return request(app.getHttpServer())
      .get('/cats/1')
      .expect(200)
      .expect({
        data: catsService.findOne(),
      });
  });

  afterAll(async () => {
    await app.close();
  });
});

解决方案

问题核心是控制器的findOne方法作为普通函数,在NestJS处理HTTP请求时丢失了this上下文,导致无法访问注入的catsService。可以通过以下两种方式修复:

方式1:将控制器方法改为箭头函数

箭头函数会自动绑定当前类实例的this,避免上下文丢失:

@Controller('cats')
export class CatsController {
  constructor(
    private readonly catsService: CatsService,
  ) {}

  @Get(':catId')
  findOne = () => {
    console.log('catsService', this.catsService);
    return this.catsService.findOne('1');
  }
}

方式2:在构造函数中手动绑定this

通过bind方法手动将方法的this绑定到控制器实例:

@Controller('cats')
export class CatsController {
  constructor(
    private readonly catsService: CatsService,
  ) {
    this.findOne = this.findOne.bind(this);
  }

  @Get(':catId')
  findOne() {
    console.log('catsService', this.catsService);
    return this.catsService.findOne('1');
  }
}

测试代码中的overrideProvider逻辑是正确的,修复控制器的this绑定问题后,依赖注入即可正常工作,测试也能顺利执行。

内容的提问来源于stack exchange,提问作者user3666653

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 06:33:29