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

Express+Jest+Supertest多测试文件运行冲突问题求助

解决多测试文件并行时Prisma唯一约束冲突的方案

不用合并测试文件,按路由拆分测试是更合理的维护方式。针对你遇到的并行测试数据冲突问题,有以下几种可行的解决思路:

1. 让Jest串行运行测试文件

Jest默认并行执行多个测试文件,导致两个文件的beforeEach同时插入重复数据。可以强制Jest串行运行:

  • 在jest.config.js中添加配置:
    module.exports = {
      // ...其他配置
      maxWorkers: 1,
    };
    
  • 或者运行测试时添加参数:
    jest --runInBand
    

这个方案最简单,但会降低测试执行速度,适合测试用例较少的项目。

2. 为每个测试生成唯一的测试数据

在初始化数据时,给用户名、邮箱等有唯一约束的字段添加随机后缀或标识,确保不同测试文件插入的数据不重复。比如:

// 生成随机后缀,避免重复
const randomSuffix = Math.random().toString(36).slice(2, 8);

beforeEach(async () => {
  try {
    const [user, userTwo] = await Promise.all([
      client.users.create({
        data: {
          username: `foo-${randomSuffix}`,
          email: `bar-${randomSuffix}@baz.com`,
          pw: await bcrypt.hash("password", 10),
        },
      }),
      client.users.create({
        data: {
          username: `bar-${randomSuffix}`,
          email: `foo-${randomSuffix}@bar.com`,
          pw: await bcrypt.hash("password", 10),
        },
      }),
    ]);

    await Promise.all([
      client.boards.create({
        data: {
          name: "one",
          creator_id: user.id,
          created_at: new Date(200000000000),
          members: { connect: user },
        },
      }),
      client.boards.create({
        data: {
          name: "two",
          creator_id: userTwo.id,
          created_at: new Date(300000000000),
          members: { connect: userTwo },
        },
      }),
      client.boards.create({
        data: {
          name: "three",
          creator_id: user.id,
          created_at: new Date(400000000000),
          members: { connect: [user, userTwo] },
        },
      }),
    ]);
  } catch (err) {
    console.error(err);
    return;
  }
});

这个方案不影响测试并行速度,是最推荐的轻量解决方案。

3. 使用事务回滚隔离测试数据

利用数据库事务的特性,每个测试在独立事务中执行,测试结束后回滚事务,避免数据持久化到数据库。调整测试初始化逻辑如下:

let prismaTx;

beforeEach(async () => {
  // 开启事务并执行初始化操作
  prismaTx = await client.$transaction([
    client.users.create({
      data: {
        username: "foo",
        email: "bar@baz.com",
        pw: await bcrypt.hash("password", 10),
      },
    }),
    client.users.create({
      data: {
        username: "bar",
        email: "foo@bar.com",
        pw: await bcrypt.hash("password", 10),
      },
    }),
    client.boards.create({
      data: {
        name: "one",
        creator_id: (await client.users.findFirst({ where: { username: "foo" } })).id,
        created_at: new Date(200000000000),
        members: { connect: { username: "foo" } },
      },
    }),
    // ...其他看板初始化操作
  ], { isolationLevel: 'Serializable' });
});

afterEach(async () => {
  // 回滚事务,清除测试数据
  await client.$rollback(prismaTx);
});

这种方式能完全隔离每个测试的数据库操作,不会出现数据污染,但需要熟悉数据库事务特性,部分场景下可能需要调整测试逻辑。

4. 为每个测试文件分配独立测试数据库

为每个Jest工作进程创建独立的测试数据库,彻底隔离不同测试文件的数据源。可以通过JEST_WORKER_ID环境变量区分不同进程,动态连接不同数据库:

// prisma/test-client.js
const { PrismaClient } = require('@prisma/client');

const client = new PrismaClient({
  datasources: {
    db: {
      url: `postgresql://user:pass@localhost:5432/test-db-${process.env.JEST_WORKER_ID || 0}`,
    },
  },
});

module.exports = client;

测试前需要确保所有测试数据库都已创建,可以在测试脚本开头添加数据库初始化逻辑。这个方案隔离性最强,但配置和维护成本稍高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 13:16:12