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())启用了该管道,但测试环境下创建的应用实例默认不会继承这个配置,导致校验逻辑未生效。
解决步骤:
- 在测试文件中导入
ValidationPipe:import { ValidationPipe } from '@nestjs/common'; - 在
beforeAll中初始化应用后添加管道注册:app = testApp.createNestApplication(); // 启用全局校验管道 app.useGlobalPipes(new ValidationPipe()); await app.init(); - 确认你的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
相关产品推荐
相关产品推荐

