如何在Jest中验证GET接口返回数组为Flight类型?
问题
我正在开发一个API,调用GET请求/api/flights/会返回一组Flight对象,所有Flight对象属性结构一致。希望在Jest测试中验证响应体中的flights列表是否为Flight类型数组,求实现方法。
测试代码如下:
test('Show flight', async () => { const response = await supertest(app.express) .get('/api/flights/') .expect(200); //Here i want to check if response.body equals an array of Flight type });
响应体示例:
{ "flights": [ { "_id": "6300bee627fff32a054f5355", "name": "Kiyv Madrid", "from": "Kiyv", "destination": "Madrid", "transplants": [], "departureDate": "20.08.2022-09:30", "arrivalDate": "21.08.2022-01:00", "seatsCount": 150, "createdAt": "2022-08-20T11:00:54.844Z", "updatedAt": "2022-08-20T11:00:54.844Z", "__v": 0 }, { "_id": "6300bf0127fff32a054f5358", "name": "Kyiv Barcelona", "from": "Kyiv", "destination": "Barcelona", "transplants": [], "departureDate": "20.08.2022-09:30", "arrivalDate": "21.08.2022-01:00", "seatsCount": 150, "createdAt": "2022-08-20T11:01:21.853Z", "updatedAt": "2022-08-20T12:45:42.596Z", "__v": 0 }, { "_id": "6300bf2a1df953f67f0e79b5", "name": "Kyiv Madrid", "from": "Kyiv", "destination": "Madrid", "transplants": [], "departureDate": "20.08.2022-09:30", "arrivalDate": "21.08.2022-01:00", "seatsCount": 150, "createdAt": "2022-08-20T11:02:02.154Z", "updatedAt": "2022-08-20T11:02:02.154Z", "__v": 0 } ] }
Flight类型定义(flight.test.interface.ts):
interface Flight { _id: string; name: string; from: string; destination: string; transplants: string; departureDate: string; arrivalDate: string; seatsCount: number; __v: number; } export default Flight;
解决方案
首先明确:TypeScript的类型仅存在于编译阶段,运行时会被完全擦除,所以Jest无法直接验证response.body.flights是否为Flight类型数组,必须通过运行时结构校验实现。下面提供几种实用方案:
方法1:手写类型守卫函数校验
自己实现一个类型守卫函数,判断单个对象是否符合Flight结构,再遍历数组逐个验证:
import Flight from './flight.test.interface'; // 类型守卫:运行时判断对象是否符合Flight结构 function isFlight(obj: unknown): obj is Flight { if (typeof obj !== 'object' || obj === null) return false; const f = obj as Flight; // 注意:你的响应中transplants是数组,但类型定义写的是string,建议将类型修正为string[] return ( typeof f._id === 'string' && typeof f.name === 'string' && typeof f.from === 'string' && typeof f.destination === 'string' && Array.isArray(f.transplants) && typeof f.departureDate === 'string' && typeof f.arrivalDate === 'string' && typeof f.seatsCount === 'number' && typeof f.__v === 'number' ); } test('Show flight', async () => { const response = await supertest(app.express) .get('/api/flights/') .expect(200); // 先确认返回结构包含flights数组 expect(response.body).toHaveProperty('flights'); expect(Array.isArray(response.body.flights)).toBe(true); // 逐个验证数组元素是否符合Flight结构 response.body.flights.forEach(flight => { expect(isFlight(flight)).toBe(true); // 可添加细节校验,比如座位数必须为正整数 expect(flight.seatsCount).toBeGreaterThan(0); }); });
方法2:用jest-extended简化断言
借助jest-extended库提供的扩展断言,减少重复代码:
- 安装依赖:
npm install jest-extended --save-dev
- 在测试文件顶部导入扩展:
import 'jest-extended';
- 结合类型守卫使用:
test('Show flight', async () => { const response = await supertest(app.express) .get('/api/flights/') .expect(200); expect(response.body.flights).toBeArray(); expect(response.body.flights.every(isFlight)).toBe(true); });
方法3:JSON Schema校验(更严谨)
如果需要更严格的结构校验(比如字段格式、数值范围),可以用JSON Schema配合jest-json-schema:
- 安装依赖:
npm install jest-json-schema --save-dev
- 定义Flight的JSON Schema:
const flightSchema = { type: 'object', required: ['_id', 'name', 'from', 'destination', 'transplants', 'departureDate', 'arrivalDate', 'seatsCount', '__v'], properties: { _id: { type: 'string' }, name: { type: 'string' }, from: { type: 'string' }, destination: { type: 'string' }, transplants: { type: 'array', items: { type: 'string' } }, // 匹配响应中的数组类型 departureDate: { type: 'string' }, arrivalDate: { type: 'string' }, seatsCount: { type: 'integer', minimum: 1 }, // 限制座位数为正整数 __v: { type: 'integer' } }, additionalProperties: true // 允许响应包含额外字段(如createdAt、updatedAt) };
- 在测试中使用:
import { matchers } from 'jest-json-schema'; // 扩展Jest的断言方法 expect.extend(matchers); test('Show flight', async () => { const response = await supertest(app.express) .get('/api/flights/') .expect(200); expect(response.body.flights).toBeArrayOfObjects(); response.body.flights.forEach(flight => { expect(flight).toMatchSchema(flightSchema); }); });
重要提醒
- 你的Flight类型定义中
transplants为string类型,但响应体中实际是数组,二者不一致,建议将类型修正为string[],避免编译时类型错误。 - 如果响应体包含类型定义中没有的字段(如
createdAt、updatedAt),校验时需允许这些额外字段存在,否则会校验失败。
内容的提问来源于stack exchange,提问作者Solyridz3
相关产品推荐
相关产品推荐

