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

如何用Jest为Express上的GraphQL端点编写服务端验证测试用例

问题:用Jest批量测试服务端验证的输入组合

给定输入组合(已修正原代码语法错误):

const inputVariations =[
    {email:"",password:""},
    {email:"test",password:"232"},
    {email:"test.testsite.com",password:"StrongPasswd234"}
];

API验证响应示例:

// 空输入对应的响应
{
    success : false,
    errors  : [
        {field:"email",message:"Email is required."},
        {field:"password",message:"Password is required."},
    ]
}

// 无效邮箱+弱密码对应的响应
{
    success : false,
    errors  : [
        {field:"email",message:"Enter a valid email address."},
        {field:"password",message:"Password is weak."},
    ]
}

你原测试代码存在的核心问题:

  1. forEach 中使用异步函数时,Jest无法等待所有请求完成,会直接结束测试,导致断言不执行或失效
  2. 断言逻辑宽泛,仅检查错误消息是否在数组中,未对应到具体输入的预期错误
  3. 用字符串模板拼接GraphQL查询,存在注入风险且可读性差
  4. 未处理请求失败的异常情况

优化后的测试方案

方案1:用test.each批量生成独立测试用例(推荐)

Jest的test.each可以为每个输入组合生成独立测试,同时明确绑定预期结果,便于定位问题:

// 定义输入与预期错误的映射关系
const testCases = [
  // [输入数据, 预期错误列表]
  [
    { email: "", password: "" },
    [
      { field: "email", message: "Email is required." },
      { field: "password", message: "Password is required." }
    ]
  ],
  [
    { email: "test", password: "232" },
    [
      { field: "email", message: "Enter a valid email address." },
      { field: "password", message: "Password is weak." }
    ]
  ],
  [
    { email: "test.testsite.com", password: "StrongPasswd234" },
    [] // 若该输入合法,预期错误列表为空,success为true
  ]
];

test.each(testCases)('验证输入组合:email=%s, password=%s', async (input, expectedErrors) => {
  try {
    const result = await axios({
      url: 'https://myapiendpoint/graphql',
      method: 'post',
      data: {
        // 用GraphQL变量代替字符串拼接,避免注入风险
        query: `
          mutation EmailRegister($input: ManageInput!) {
            emailRegister(manageInput: $input) {
              success
              errors {
                field
                message
              }
            }
          }
        `,
        variables: {
          input: {
            email: input.email,
            password: input.password
          }
        }
      }
    });

    const { success, errors } = result.data.data.emailRegister;

    // 验证success状态:无预期错误则为true,否则为false
    expect(success).toBe(expectedErrors.length === 0);
    // 验证错误列表完全匹配(数量+内容)
    expect(errors).toEqual(expect.arrayContaining(expectedErrors));
    expect(errors.length).toBe(expectedErrors.length);
  } catch (error) {
    // 捕获请求异常,避免测试静默失败
    throw new Error(`请求失败: ${error.message}`);
  }
});

方案2:用Promise.all在单个测试块中完成批量验证

如果需要在一个it块中执行所有测试,需用Promise.all确保Jest等待所有异步请求完成:

it('register validation for email and password', async () => {
  const inputVariations = [
    { email: "", password: "" },
    { email: "test", password: "232" },
    { email: "test.testsite.com", password: "StrongPasswd234" }
  ];

  // 映射每个输入对应的预期错误
  const expectedErrorsMap = new Map([
    [JSON.stringify(inputVariations[0]), [
      { field: "email", message: "Email is required." },
      { field: "password", message: "Password is required." }
    ]],
    [JSON.stringify(inputVariations[1]), [
      { field: "email", message: "Enter a valid email address." },
      { field: "password", message: "Password is weak." }
    ]],
    [JSON.stringify(inputVariations[2]), []]
  ]);

  // 用Promise.all等待所有请求完成
  await Promise.all(inputVariations.map(async (input) => {
    const result = await axios({
      url: 'https://myapiendpoint/graphql',
      method: 'post',
      data: {
        query: `
          mutation EmailRegister($input: ManageInput!) {
            emailRegister(manageInput: $input) {
              success
              errors {
                field
                message
              }
            }
          }
        `,
        variables: { input }
      }
    });

    const { success, errors } = result.data.data.emailRegister;
    const expectedErrors = expectedErrorsMap.get(JSON.stringify(input));

    expect(success).toBe(expectedErrors.length === 0);
    expect(errors).toEqual(expect.arrayContaining(expectedErrors));
    expect(errors.length).toBe(expectedErrors.length);
  }));
});

关键优化说明

  1. GraphQL变量替代字符串拼接:避免注入风险,提升代码可读性和维护性
  2. 明确预期结果:每个输入绑定对应错误列表,断言更精准
  3. 异步等待处理:确保Jest等待所有异步操作完成,不会提前结束测试
  4. 异常捕获:添加try/catch捕获请求异常,避免测试静默失败
  5. 精确断言:不仅检查错误存在,还验证错误数量和内容完全匹配

内容的提问来源于stack exchange,提问作者Ajith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:43:12