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

Jest+Supertest批量运行接口测试报Mongo E11000错误且delete测试失败

问题产生原因

  • 测试用例执行顺序不符合预期:Jest默认开启测试用例并发执行,不会严格按照你编写的get→post→delete顺序执行,大概率delete用例会早于post用例运行,此时payload.id还是你初始化的假ID6156c95c9ecf28237844489b,数据库中不存在对应记录,自然返回deletedCount为0。
  • 接口异步逻辑存在缺陷:/add接口中的todo.save()是Mongo异步操作,你没有加await等待操作完成就直接返回了todo对象,极端情况会出现接口已经返回_id,但数据还没落地到数据库,此时后续delete操作依然找不到对应数据。
  • 测试环境没有做脏数据清理:每次运行测试前没有清空测试库的残留数据,如果你的Todos集合的item字段设置了唯一索引,重复插入item: "test"就会抛出E11000 duplicate key重复键错误。

解决方案

1. 修复接口异步逻辑

先修改/add接口,确保数据写入数据库后再返回响应:

app.post("/add", async (req, res) => {
  const { item, status } = req.body;
  const todo = new Todos({
    item,
  });
  await todo.save(); // 新增await等待保存完成
  res.send(todo);
});

2. 调整测试逻辑,避免脏数据、保证执行顺序

重写测试用例,新增前置钩子清理测试数据,改用async/await写法保证用例执行的顺序依赖:

const request = require("supertest"); 
const app = require("../server");
const Todos = require("../你的Todos模型文件路径"); // 导入你的Mongo模型

describe("testing Todos API", () => {
  let payload = { id: "" };
  let item = { item: "test" };

  // 每次执行测试用例前清空Todos集合,避免脏数据
  beforeEach(async () => {
    await Todos.deleteMany({});
  })

  it("get", async () => {
    const res = await request(app).get("/").expect(200);
    expect(res.body).toEqual({ name: "bob" });
    expect(res.body.name).toEqual("bob");
  });

  it("post", async () => {
    const res = await request(app)
      .post("/add")
      .send(item)
      .expect(200);
    payload.id = res.body._id;
    expect(res.body.item).toEqual(item.item);
  });

  it("delete", async () => {
    const res = await request(app)
      .delete("/delete")
      .send(payload);
    expect(res.body.deletedCount).toEqual(1);
  });
});

3. 强制测试串行执行(可选)

如果调整后仍有执行顺序问题,可以在运行Jest时添加--runInBand参数,强制所有测试用例串行执行,完全避免并发打乱顺序的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:48:02