修复不稳定测试 fixing-flaky-tests

这个技能用于诊断和修复软件测试中的不稳定问题,特别是当测试在独立运行时通过但在并发运行时失败的情况。它涵盖共享状态隔离、竞态条件处理、资源冲突解决,提供多种编程语言和框架的实用模式和工具,以提高测试的稳定性和可靠性。关键词:不稳定测试、并发测试、共享状态、竞态条件、资源隔离、测试自动化。

测试 0 次安装 0 次浏览 更新于 3/5/2026

name: fixing-flaky-tests description: 诊断和修复在独立运行时通过但在并发运行时失败的测试。覆盖共享状态隔离和资源冲突。参考条件等待技能来处理定时问题。

修复不稳定测试

目标症状: 测试在单独运行时通过,但与其他测试一起运行时失败。

先诊断

测试单独通过,与其他测试一起失败?
    │
    ├─ 每次都出现相同错误 → 共享状态
    │   └─ 数据库、全局变量、文件、单例
    │
    ├─ 随机/定时失败 → 竞态条件
    │   └─ 使用`条件等待`技能
    │
    └─ 资源错误(端口、文件锁) → 资源冲突
        └─ 每个测试/工作线程需要唯一资源

快速诊断:

  1. 单独运行失败测试10次 - 是否总是通过?
  2. 与套件一起运行失败测试10次 - 相同错误还是不同?
  3. 检查错误消息 - 是否提到端口/文件/连接?

共享状态(确定性失败)

测试污染了其他测试依赖的状态。通过每个测试隔离状态来修复。

状态类型 隔离模式
数据库 事务回滚、保存点、工作线程特定数据库
全局变量 beforeEach/afterEach中重置
单例 每个测试提供新实例
模块状态 jest.resetModules()或等效方法
文件 每个测试使用唯一路径、临时目录
环境变量 在设置/清理中保存/恢复

数据库隔离(最常见):

# Python:保存点回滚 - 每个测试回滚
@pytest.fixture
async def db_session(db_engine):
    async with db_engine.connect() as conn:
        await conn.begin()
        await conn.begin_nested()  # 保存点
        # ... 生成会话 ...
        await conn.rollback()  # 所有更改消失
// Jest:在测试之间重置模拟
beforeEach(() => {
  jest.clearAllMocks()
  jest.resetModules()  // 在测试前清除模块缓存
})

afterEach(() => {
  jest.restoreAllMocks()  // 恢复被监视的函数
})

查看语言特定参考以获取完整模式。

竞态条件(随机失败)

测试不等待异步操作完成。

使用条件等待技能 获取详细模式,包括:

  • 框架特定等待(Testing Library findBy、Playwright自动等待)
  • 自定义轮询助手
  • 何时可接受任意超时

快速总结: 等待条件,而不是时间:

// 不好
await sleep(500)

// 好
await waitFor(() => expect(result).toBe('done'))

资源冲突(端口/文件错误)

多个测试或工作线程竞争相同资源。

工作线程特定资源:

# Python pytest-xdist:每个工作线程唯一数据库
@pytest.fixture(scope="session")
def database_url(worker_id):
    if worker_id == "master":
        return "postgresql://localhost/test"
    return f"postgresql://localhost/test_{worker_id}"
// Jest/Node:动态端口分配
const server = app.listen(0)  // 操作系统分配可用端口
const port = server.address().port

文件冲突:

import tempfile

@pytest.fixture
def temp_dir():
    with tempfile.TemporaryDirectory() as d:
        yield d

语言特定隔离模式

技术栈 参考
Python (pytest, SQLAlchemy) references/python.md
Jest / Testing Library references/jest.md
Playwright E2E references/playwright.md

验证

修复后,验证修复是否有效:

# 多次运行特定测试
pytest tests/test_flaky.py -x --count=20

# 并行运行
pytest -n auto

# Jest等效
jest --runInBand  # 首先验证串行工作
jest              # 然后验证并行工作