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

如何编写Jest测试验证NestJS控制器的Interceptor已被调用?

验证NestJS拦截器绑定生效的Jest测试方案

针对你要验证LoggingInterceptor是否被正确调用的需求,这里提供几种实用的Jest测试方案:

1. 模拟拦截器类并跟踪调用

通过jest.mock直接模拟拦截器的实现,拦截其导入并跟踪intercept方法的调用情况,适合单元测试场景:

// app.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingInterceptor } from './transform.interceptor';

// 模拟LoggingInterceptor,实现mock的intercept方法
jest.mock('./transform.interceptor', () => ({
  LoggingInterceptor: jest.fn().mockImplementation(() => ({
    intercept: jest.fn((context, next) => next.handle()),
  })),
}));

describe('AppController', () => {
  let appController: AppController;
  let loggingInterceptor: LoggingInterceptor;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [AppService],
    }).compile();

    appController = module.get(AppController);
    // 获取mock生成的拦截器实例
    loggingInterceptor = (LoggingInterceptor as jest.Mock).mock.instances[0];
  });

  describe('getHello', () => {
    it('应触发LoggingInterceptor的intercept方法', async () => {
      await appController.getHello();
      expect(loggingInterceptor.intercept).toHaveBeenCalled();
    });
  });
});

2. 用SuperTest发起真实请求验证

如果需要验证完整的HTTP请求流程中拦截器是否生效,可以用SuperTest编写e2e测试:

// app.e2e-spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
import { LoggingInterceptor } from './../src/transform.interceptor';

// 模拟拦截器类
jest.mock('./../src/transform.interceptor', () => ({
  LoggingInterceptor: jest.fn().mockImplementation(() => ({
    intercept: jest.fn((context, next) => next.handle()),
  })),
}));

describe('AppController (e2e)', () => {
  let app: INestApplication;
  let loggingInterceptor: LoggingInterceptor;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();

    loggingInterceptor = (LoggingInterceptor as jest.Mock).mock.instances[0];
  });

  it('GET / 应触发LoggingInterceptor', async () => {
    await request(app.getHttpServer()).get('/').expect(200);
    expect(loggingInterceptor.intercept).toHaveBeenCalled();
  });
});

3. 覆盖测试模块中的拦截器依赖

如果拦截器是全局注册或通过APP_INTERCEPTOR令牌提供的,可以通过overrideProvider替换为mock实例:

// app.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingInterceptor } from './transform.interceptor';
import { APP_INTERCEPTOR } from '@nestjs/core';

// 定义mock拦截器实例
const mockLoggingInterceptor = {
  intercept: jest.fn((context, next) => next.handle()),
};

describe('AppController', () => {
  let appController: AppController;
  let loggingInterceptor: typeof mockLoggingInterceptor;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [
        AppService,
        {
          provide: APP_INTERCEPTOR,
          useClass: LoggingInterceptor,
        },
      ],
    })
      .overrideProvider(APP_INTERCEPTOR)
      .useValue(mockLoggingInterceptor)
      .compile();

    appController = module.get(AppController);
    loggingInterceptor = module.get(APP_INTERCEPTOR);
  });

  it('调用getHello时应触发拦截器', async () => {
    await appController.getHello();
    expect(loggingInterceptor.intercept).toHaveBeenCalled();
  });
});

注意事项

  • 确保mock的intercept方法调用next.handle(),否则会中断请求处理流程
  • 单元测试适合快速验证拦截器绑定,e2e测试更贴近真实运行场景
  • 如果拦截器依赖其他服务,需要在测试模块中提供对应的模拟服务

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:22:15