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

NestJS+Supertest测试Bad Request场景失败,返回200而非400

问题

用NestJS开发示例API时,为接收经纬度查询参数并返回附近餐厅的接口编写测试,已添加查询参数类型校验,但测试中无法触发Bad Request场景:成功请求返回200正常,但传入无效纬度时,测试请求始终返回200而非预期的400,终端报错expected 400 "Bad Request", got 200 "OK"。但在浏览器或Postman中发送相同请求能正常返回400。

测试代码

import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest';
import { RestaurantController } from './restaurant.controller';
import { RestaurantService } from './restaurant.service';
import { successResponse } from '../../test/mocks';

describe('RestaurantController', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const testApp: TestingModule = await Test.createTestingModule({
      controllers: [RestaurantController],
      providers: [RestaurantService],
    }).compile();

    app = testApp.createNestApplication();
    await app.init();
  });

  describe('GET /restaurant/location', () => {
    const url = '/restaurant/location';

    it('should return a list of near restaurants', () => {
      return request(app.getHttpServer())
        .get(url)
        .query({ latitude: -34.661369, longitude: -58.362257 })
        .expect(200)
        .expect(successResponse);
    });

    it('should throw an error because the latitude is invalid', () => {
      return request(app.getHttpServer())
        .get(url)
        .query({ latitude: 'I am not a valid latitude', longitude: -58.362257 })
        .expect(400);
    });
  });
});

终端报错信息

FAIL  src/restaurant/restaurant.controller.spec.ts
  ● RestaurantController › GET /restaurant/location › should throw an error because the latitude is invalid

    expected 400 "Bad Request", got 200 "OK"

      44 |         .get(`${url}?latitude=invalid&longitude=-58.362257`)
      45 |         .query({ latitude: 'I am not a valid latitude', longitude: -58.362257 })
    > 46 |         .expect(400);
         |          ^
      47 |     });
      48 |   });
      49 | });

      at Object.<anonymous> (src/restaurant/restaurant.controller.spec.ts:46:10)
      ----
      at Test._assertStatus (node_modules/supertest/lib/test.js:252:14)
      at node_modules/supertest/lib/test.js:306:17
      at Test._assertFunction (node_modules/supertest/lib/test.js:285:13)
      at Test.assert (node_modules/supertest/lib/test.js:164:23)
      at Server.localAssert (node_modules/supertest/lib/test.js:120:14)
解决方案

核心问题是测试模块中未启用ValidationPipe。NestJS的参数校验依赖全局或局部注册的ValidationPipe,正常启动应用时你应该在main.ts中通过app.useGlobalPipes(new ValidationPipe())启用了该管道,但测试环境下创建的应用实例默认不会继承这个配置,导致校验逻辑未生效。

解决步骤:

  1. 在测试文件中导入ValidationPipe:
    import { ValidationPipe } from '@nestjs/common';
    
  2. 在beforeAll中初始化应用后添加管道注册:
    app = testApp.createNestApplication();
    // 启用全局校验管道
    app.useGlobalPipes(new ValidationPipe());
    await app.init();
    
  3. 确认你的DTO已正确添加校验装饰器(确保类型转换和范围校验逻辑完整):
    import { IsNumber, Min, Max } from 'class-validator';
    import { Transform } from 'class-transformer';
    
    export class LocationQueryDto {
      @Transform(({ value }) => parseFloat(value))
      @IsNumber()
      @Min(-90)
      @Max(90)
      latitude: number;
    
      @Transform(({ value }) => parseFloat(value))
      @IsNumber()
      @Min(-180)
      @Max(180)
      longitude: number;
    }
    

修改后的测试文件会启用校验管道,此时传入无效纬度的请求会触发400错误,测试就能通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 11:54:15