supertest/jest测试不同路径总命中同一个@Get(':id')端点,需配置什么?
问题根因
- NestJS 路由采用先注册先匹配规则,不会自动做路径最优匹配,动态参数路由
/:id可以匹配所有/xxx格式的路径,只要它的注册顺序早于其他固定前缀的同层级路由,所有对应请求都会优先命中它。 @nestjsx/crud装饰器会自动生成默认CRUD路由,其中getOneBase接口对应的就是GET /:id路由,且这部分自动生成的路由的注册顺序早于你在控制器里手动定义的所有自定义路由,所以不管你手动定义的@Get('status')、@Get('list/:algorithmId')写在什么位置,默认生成的/:id都会先匹配到所有请求,导致你自定义的路由永远不会被触发。- 单个测试能正常运行的原因是:你注释其他两个测试时,大概率同步注释了对应的自定义路由,或者单测运行时临时跳过了Crud默认路由的注册,才会刚好命中你保留的对应接口。
所需配置调整
不需要修改你的完整链路测试逻辑,也不需要做接口mock,只需要调整@Crud装饰器配置和自定义路由顺序即可:
- 禁用或修改@Crud自动生成的冲突路由
在@Crud配置中排除默认生成的getOneBase路由,避免它和你自定义的@Get(':id')冲突,或者修改默认路由的路径避免匹配冲突:
import { Crud } from '@nestjsx/crud'; @Crud({ model: { type: InferenceFile, // 替换为你的实体类 }, routes: { getOneBase: { // 方案1:禁用默认生成的getOne接口,完全使用你自定义的@Get(':id') exclude: true, // 方案2:修改默认路由的前缀,避免和你的其他路由冲突 // path: 'detail/:id' } } }) @Controller('inference-files') export class InferenceFilesController { // 你的自定义路由 }
- 调整自定义路由的定义顺序
所有固定前缀的路由必须放在动态参数路由的前面,避免自定义的动态路由拦截其他同层级路由:
// 固定前缀路由放前面 @Get('list/:algorithmId') async getListByAlgorithmId(@Param('algorithmId') algorithmId: string) { // 你的逻辑 } @Get('status') async getStatus() { // 你的逻辑 } // 动态参数路由放最后 @Get(':id') async getOneById(@Param('id') id: string) { // 你的逻辑 }
- 单测初始化配置(可选,避免实例复用导致的异常)
如果你的单测存在复用Nest应用实例的情况,需要确保每个测试用例运行前都会初始化全新的实例,避免路由注册重复导致的匹配异常:
import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import * as request from 'supertest'; import { AppModule } from '../src/app.module'; describe('InferenceFilesController (e2e)', () => { let app: INestApplication; beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); await app.init(); }); afterEach(async () => { await app.close(); }); it('/inference-files/status (GET)', () => { return request(app.getHttpServer()) .get('/inference-files/status') .expect(200); }); // 其他测试用例 });
以上调整完成后即可正常匹配所有路由,不需要修改你的测试逻辑和数据库配置。
内容的提问来源于stack exchange,提问作者kato d
相关产品推荐
相关产品推荐

