Jest测试NestJS DTO校验缺失子字段错误 Postman调用正常
问题原因
- 单元测试核心错误:
ValidationPipe.transform方法的第一个入参才是待校验的实际 payload,你当前传入的是<ApiDTO>{}空对象,没有携带Item字段,自然不会触发子DTO的校验逻辑。你写在ArgumentMetadata.data字段的JSON串是无效配置,ArgumentMetadata的data属性存储的是参数装饰器的自定义参数(比如@Body('fileName')里的fileName),和待校验内容无关。 - E2E测试语法错误:数组值对比不能用
toBe(toBe是引用匹配),必须用toEqual做值匹配,否则即使返回的错误内容正确也会断言失败。 - 通用可选问题:class-validator默认不会校验不存在的字段,如果希望强制要求接口必须传
Item字段、漏传时也抛出错误,可以在父DTO的Item字段上添加@IsDefined()装饰器。
修复方案
1. 修正单元测试代码
调整待校验payload和metadata配置即可:
import { ArgumentMetadata, ValidationPipe } from '@nestjs/common'; import { ApiDTO } from './api.dto'; describe('ApiDto', () => { it('should be defined', () => { expect(new ApiDTO()).toBeDefined(); }); it('should validate the ApiDTO definition', async () => { const target: ValidationPipe = new ValidationPipe({ transform: true, whitelist: true, }); const metadata: ArgumentMetadata = { type: 'body', metatype: ApiDTO, data: '', // 无参数@Body()装饰器对应data为空 }; // 和Postman请求保持一致的待校验 payload const testPayload = { Item: {} }; const Expected: string[] = [ 'FileName must be longer than or equal to 1 characters', 'FileName must be a string', 'Item.Data must be longer than or equal to 2 characters', 'Item.Data must be a number string', ]; await target.transform(testPayload, metadata).catch((err) => { expect(err.getResponse().message).toEqual(Expected); }); }); });
2. 修正E2E测试代码
把数组对比方法改为toEqual:
// 其他代码不变 expect(ResponseData$.body.message).toEqual(Expected);
3. 可选:增强DTO健壮性(按需添加)
如果希望强制要求Item字段必须传递,漏传时也抛出对应错误,可以给ApiDTO的Item字段添加@IsDefined()校验:
import { IsDefined } from 'class-validator'; export class ApiDTO { @IsString() @MinLength(1) public readonly FileName: string; @IsDefined() @ValidateNested() @Type(() => ItemDataDTO) Item: ItemDataDTO; }
内容的提问来源于stack exchange,提问作者Steven Scott
相关产品推荐
相关产品推荐

