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

Express接口测试异常:重复商品用例无法获取422状态码

问题:重复商品订单测试用例无法正确断言状态码

问题场景

我在测试一个Express + TypeScript的结账接口,其中检测重复商品的测试用例明明进入了catch块并返回了错误消息,但测试里始终拿不到响应状态码,output.status一直是undefined。移除状态码断言后测试能通过,但其他测试用例(比如无效CPF)却能正常获取状态码。

接口代码

import express, { Request, Response } from "express";
import { validate } from "./validator";
import pgp from "pg-promise";
const app = express();
app.use(express.json());

app.post("/checkout", async function (req: Request, res: Response) {
  const connection = pgp()("postgres://postgres:dev123@localhost:5432/tdd-app");
  try {
    const isValid = validate(req.body.cpf);
    if (!isValid) throw new Error("Invalid cpf");

    const output: Output = {
      total: 0,
    };
    const items: number[] = [];
    if (req.body.items) {
      for (const item of req.body.items) {
        if (item.quantity <= 0) throw new Error("Invalid quantity");
        if (items.includes(item.idProduct)) throw new Error("Duplicated item");
        const [productData] = await connection.query(
          "SELECT * FROM cccat10.product WHERE id_product = $1",
          item.idProduct
        );
        output.total += parseFloat(productData.price) * item.quantity;
        items.push(item.idProduct);
      }
    }

    if (req.body.coupon) {
      const [couponData] = await connection.query(
        "SELECT * FROM cccat10.coupon WHERE code = $1",
        [req.body.coupon]
      );
      if (couponData.expire_date.getTime() >= new Date().getTime()) {
        const percentage = parseFloat(couponData.percentage);
        output.total -= (output.total * percentage) / 100;
      }
    }
    res.json(output);
  } catch (e: any) {
    res.status(422).json({
      message: e.message,
    });
  } finally {
    await connection.$pool.end();
  }
});

type Output = {
  total: number;
  message?: string;
};

app.listen(3000);

有问题的测试用例

test("Shouldnt create an order with duplicated item", async function () {
  const input = {
    cpf: "684.053.160-00",
    items: [
      { idProduct: 1, quantity: 1 },
      { idProduct: 1, quantity: 1 },
    ],
  };
  const response = await axios.post("http://localhost:3000/checkout", input);
  const output = response.data;
  expect(output.status).toBe(422);
  expect(output.message).toBe("Duplicated item");
});

正常工作的测试用例(对比参考)

test("Shouldnt accept an order with an invalid cpf ", async function () {
  const input = {
    cpf: "406.302.170-27",
  };
  const response = await axios.post("http://localhost:3000/checkout", input);
  const output = response.data;
  expect(response.status).toBe(422);
  expect(output.message).toBe("Invalid cpf");
});

问题修复方案

问题根源在于测试用例的断言对象错误:

  • HTTP响应状态码是axios返回的**response对象**的属性,不是响应体(output = response.data)的属性
  • 你在有问题的测试里错误地断言了output.status,正确做法是和正常测试用例一样,断言response.status

修改后的测试用例:

test("Shouldnt create an order with duplicated item", async function () {
  const input = {
    cpf: "684.053.160-00",
    items: [
      { idProduct: 1, quantity: 1 },
      { idProduct: 1, quantity: 1 },
    ],
  };
  const response = await axios.post("http://localhost:3000/checkout", input);
  const output = response.data;
  expect(response.status).toBe(422); // 改为断言response对象的status属性
  expect(output.message).toBe("Duplicated item");
});

补充说明:
当接口返回422状态码时,axios的response对象会包含status字段,但你在catch块里返回的响应体只有message字段,并没有status,所以之前的output.status自然是undefined。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:31:02