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

使用Jest测试对象集合结构是否有更优的实现方案?

你当前的实现是可以正常工作的,能准确校验返回的每个exercise对象的键集合和预期完全一致,没有多余也没有缺失,属于合理的实现方式,但是存在几个可优化的空间,同时也有更简洁高效的Jest实践可以参考。

现有实现的可优化点

  • 空集合场景会直接通过测试,无法校验listAllExercises有没有正常返回数据
  • 用forEach遍历出错时,只会抛出键不匹配的错误,无法直观看到是第几个exercise、对应哪条数据出问题
  • 仅校验键的存在性,不会校验对应值的类型是否符合预期,比如level是不是数字、is_poly_articular是不是布尔值这类问题发现不了

优化方案参考

方案1:原生Jest无额外依赖,优化错误定位和边界校验

不需要引入任何第三方依赖,只对现有写法做小调整就能大幅提升测试体验:

const allExercises = listAllExercises()
const REQUIRED_KEYS = [
  "name",
  "execution",
  "level",
  "is_poly_articular",
  "practice",
  "gender",
  "body_focus",
]

describe("listAllExercises | should return all exercises", () => {
  // 先校验返回集合非空,避免空数组直接过测
  test("should return non-empty exercise list", () => {
    expect(allExercises).not.toHaveLength(0)
  })

  // 用.each遍历每个exercise作为独立用例,出错直接定位下标
  test.each(allExercises)("exercise #%# has correct structure", (exercise) => {
    // 校验所有必填键都存在
    REQUIRED_KEYS.forEach(key => {
      expect(exercise).toHaveProperty(key)
    })
    // 校验不存在多余的键
    expect(Object.keys(exercise)).toHaveLength(REQUIRED_KEYS.length)

    // 可选:扩展值类型校验,更严谨
    expect(typeof exercise.name).toBe('string')
    expect(typeof exercise.is_poly_articular).toBe('boolean')
    // 其他字段按需加类型校验
  })
})

方案2:用内置匹配器简化写法,支持类型校验

如果不需要严格禁止多余键,只要求所有必填键存在,可直接用expect.objectContaining匹配器,不需要手动遍历键列表:

test.each(allExercises)("exercise #%# has all required keys", (exercise) => {
  expect(exercise).toEqual(expect.objectContaining({
    name: expect.any(String),
    execution: expect.any(String),
    level: expect.any(Number),
    is_poly_articular: expect.any(Boolean),
    practice: expect.any(String),
    gender: expect.any(String),
    body_focus: expect.any(String),
  }))
})

如果需要严格禁止多余键,额外加一行expect(Object.keys(exercise)).toHaveLength(7)即可。

方案3:复杂场景用Zod做结构校验

如果结构校验逻辑复杂、或者需要复用结构定义,推荐引入Zod定义Schema,校验精度更高、错误信息更清晰:
首先定义可复用的结构Schema:

import { z } from 'zod'

const ExerciseSchema = z.object({
  name: z.string(),
  execution: z.string(),
  level: z.enum(['beginner', 'intermediate', 'advanced']), // 支持限定枚举值
  is_poly_articular: z.boolean(),
  practice: z.string(),
  gender: z.enum(['male', 'female', 'neutral']),
  body_focus: z.string(),
})

测试代码:

test.each(allExercises)("exercise #%# matches structure schema", (exercise) => {
  const parseResult = ExerciseSchema.safeParse(exercise)
  // 出错时parseResult.error会返回非常详细的错误信息,精准定位问题字段
  expect(parseResult.success).toBe(true)
})

内容的提问来源于stack exchange,提问作者Jean-Baptiste THERY

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 21:27:03