ln-635-test-isolation-auditor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Test Isolation & Anti-Patterns Auditor (L3 Worker)

测试隔离与反模式审计器(L3工作器)

Specialized worker auditing test isolation and detecting anti-patterns.
专注于审计测试隔离性并检测反模式的工作器。

Purpose & Scope

目标与范围

  • Worker in ln-630 coordinator pipeline
  • Audit Test Isolation (Category 5: Medium Priority)
  • Audit Anti-Patterns (Category 6: Medium Priority)
  • Check determinism (no flaky tests)
  • Calculate compliance score (X/10)
  • ln-630协调器流水线中的工作器
  • 审计测试隔离性(类别5:中等优先级)
  • 审计反模式(类别6:中等优先级)
  • 检查确定性(无不稳定测试)
  • 计算合规分数(X/10)

Inputs (from Coordinator)

输入(来自协调器)

Receives
contextStore
with isolation checklist, anti-patterns catalog, test file list.
接收包含隔离性检查清单、反模式目录、测试文件列表的
contextStore

Workflow

工作流程

  1. Parse context
  2. Check isolation for 6 categories
  3. Check determinism
  4. Detect 6 anti-patterns
  5. Collect findings
  6. Calculate score
  7. Return JSON
  1. 解析上下文
  2. 检查6类隔离性
  3. 检查确定性
  4. 检测6种反模式
  5. 收集问题结果
  6. 计算分数
  7. 返回JSON

Audit Rules: Test Isolation

审计规则:测试隔离性

1. External APIs

1. 外部API

Good: Mocked (jest.mock, sinon, nock) Bad: Real HTTP calls to external APIs
Detection:
  • Grep for
    axios.get
    ,
    fetch(
    ,
    http.request
    without mocks
  • Check if test makes actual network calls
Severity: HIGH
Recommendation: Mock external APIs with
nock
or
jest.mock
Effort: M
良好实践: 已Mock(jest.mock、sinon、nock) 不良实践: 对外部API发起真实HTTP请求
检测方式:
  • 搜索
    axios.get
    fetch(
    http.request
    且未使用Mock的情况
  • 检查测试是否发起实际网络请求
严重程度:
建议: 使用
nock
jest.mock
Mock外部API
整改工作量: M

2. Database

2. 数据库

Good: In-memory DB (sqlite :memory:) or mocked Bad: Real database (PostgreSQL, MySQL)
Detection:
  • Check DB connection strings (localhost:5432, real DB URL)
  • Grep for
    beforeAll(async () => { await db.connect() })
    without
    :memory:
Severity: MEDIUM
Recommendation: Use in-memory DB or mock DB calls
Effort: M-L
良好实践: 内存数据库(sqlite :memory:)或已Mock 不良实践: 真实数据库(PostgreSQL、MySQL)
检测方式:
  • 检查数据库连接字符串(localhost:5432、真实数据库URL)
  • 搜索
    beforeAll(async () => { await db.connect() })
    且未使用
    :memory:
    的情况
严重程度:
建议: 使用内存数据库或Mock数据库调用
整改工作量: M-L

3. File System

3. 文件系统

Good: Mocked (mock-fs, vol) Bad: Real file reads/writes
Detection:
  • Grep for
    fs.readFile
    ,
    fs.writeFile
    without mocks
  • Check if test creates/deletes real files
Severity: MEDIUM
Recommendation: Mock file system with
mock-fs
Effort: S-M
良好实践: 已Mock(mock-fs、vol) 不良实践: 真实文件读/写操作
检测方式:
  • 搜索
    fs.readFile
    fs.writeFile
    且未使用Mock的情况
  • 检查测试是否创建/删除真实文件
严重程度:
建议: 使用
mock-fs
Mock文件系统
整改工作量: S-M

4. Time/Date

4. 时间/日期

Good: Mocked (jest.useFakeTimers, sinon.useFakeTimers) Bad:
new Date()
,
Date.now()
without mocks
Detection:
  • Grep for
    new Date()
    in test files without
    useFakeTimers
Severity: MEDIUM
Recommendation: Mock time with
jest.useFakeTimers()
Effort: S
良好实践: 已Mock(jest.useFakeTimers、sinon.useFakeTimers) 不良实践: 未Mock的
new Date()
Date.now()
检测方式:
  • 搜索测试文件中未搭配
    useFakeTimers
    new Date()
严重程度:
建议: 使用
jest.useFakeTimers()
Mock时间
整改工作量: S

5. Random

5. 随机数

Good: Seeded random (Math.seedrandom, fixed seed) Bad:
Math.random()
without seed
Detection:
  • Grep for
    Math.random()
    without seed setup
Severity: LOW
Recommendation: Use seeded random for deterministic tests
Effort: S
良好实践: 带种子的随机数(Math.seedrandom、固定种子) 不良实践: 未设置种子的
Math.random()
检测方式:
  • 搜索未设置种子的
    Math.random()
严重程度:
建议: 使用带种子的随机数以保证测试确定性
整改工作量: S

6. Network

6. 网络

Good: Mocked (supertest for Express, no real ports) Bad: Real network requests (
localhost:3000
, binding to port)
Detection:
  • Grep for
    app.listen(3000)
    in tests
  • Check for real HTTP requests
Severity: MEDIUM
Recommendation: Use
supertest
(no real port)
Effort: M
良好实践: 已Mock(Express使用supertest,不使用真实端口) 不良实践: 真实网络请求(
localhost:3000
、绑定到真实端口)
检测方式:
  • 搜索测试中的
    app.listen(3000)
  • 检查是否存在真实HTTP请求
严重程度:
建议: 使用
supertest
(不使用真实端口)
整改工作量: M

Audit Rules: Determinism

审计规则:确定性

1. Flaky Tests

1. 不稳定测试

What: Tests that pass/fail randomly
Detection:
  • Run tests multiple times, check for inconsistent results
  • Grep for
    setTimeout
    ,
    setInterval
    without proper awaits
  • Check for race conditions (async operations not awaited)
Severity: HIGH
Recommendation: Fix race conditions, use proper async/await
Effort: M-L
定义: 随机通过/失败的测试
检测方式:
  • 多次运行测试,检查结果是否不一致
  • 搜索未正确使用await的
    setTimeout
    setInterval
  • 检查是否存在竞态条件(未等待的异步操作)
严重程度:
建议: 修复竞态条件,正确使用async/await
整改工作量: M-L

2. Time-Dependent Assertions

2. 时间依赖断言

What: Assertions on current time (
expect(timestamp).toBeCloseTo(Date.now())
)
Detection:
  • Grep for
    Date.now()
    ,
    new Date()
    in assertions
Severity: MEDIUM
Recommendation: Mock time
Effort: S
定义: 对当前时间的断言(
expect(timestamp).toBeCloseTo(Date.now())
检测方式:
  • 搜索断言中的
    Date.now()
    new Date()
严重程度:
建议: Mock时间
整改工作量: S

3. Order-Dependent Tests

3. 顺序依赖测试

What: Tests that fail when run in different order
Detection:
  • Run tests in random order, check for failures
  • Grep for shared mutable state between tests
Severity: MEDIUM
Recommendation: Isolate tests, reset state in beforeEach
Effort: M
定义: 运行顺序改变时会失败的测试
检测方式:
  • 随机顺序运行测试,检查是否失败
  • 搜索测试间共享的可变状态
严重程度:
建议: 隔离测试,在beforeEach中重置状态
整改工作量: M

4. Shared Mutable State

4. 共享可变状态

What: Global variables modified across tests
Detection:
  • Grep for
    let globalVar
    at module level
  • Check for state shared between tests
Severity: MEDIUM
Recommendation: Use
beforeEach
to reset state
Effort: S-M
定义: 跨测试修改的全局变量
检测方式:
  • 搜索模块级别的
    let globalVar
  • 检查测试间是否存在共享状态
严重程度:
建议: 使用
beforeEach
重置状态
整改工作量: S-M

Audit Rules: Anti-Patterns

审计规则:反模式

1. The Liar (Always Passes)

1. 说谎者(始终通过)

What: Test with no assertions or trivial assertion (
expect().toBeTruthy()
)
Detection:
  • Count assertions per test
  • If 0 assertions or only
    toBeTruthy()
    → Liar
Severity: HIGH
Recommendation: Add specific assertions or delete test
Effort: S
Example:
  • BAD (Liar): Test calls
    createUser()
    but has NO assertions — always passes even if function breaks
  • GOOD: Test calls
    createUser()
    and asserts
    user.name
    equals 'Alice',
    user.id
    is defined
定义: 没有断言或仅包含 trivial 断言(
expect().toBeTruthy()
)的测试
检测方式:
  • 统计每个测试的断言数量
  • 若断言数为0或仅使用
    toBeTruthy()
    → 属于说谎者
严重程度:
建议: 添加具体断言或删除测试
整改工作量: S
示例:
  • 不良实践(说谎者): 测试调用
    createUser()
    但无任何断言——即使函数出错也始终通过
  • 良好实践: 测试调用
    createUser()
    并断言
    user.name
    等于'Alice'、
    user.id
    已定义

2. The Giant (>100 lines)

2. 巨人(超过100行)

What: Test with >100 lines, testing too many scenarios
Detection:
  • Count lines per test
  • If >100 lines → Giant
Severity: MEDIUM
Recommendation: Split into focused tests (one scenario per test)
Effort: S-M
定义: 超过100行、测试过多场景的测试
检测方式:
  • 统计每个测试的行数
  • 若超过100行 → 属于巨人
严重程度:
建议: 拆分为聚焦的测试(每个测试对应一个场景)
整改工作量: S-M

3. Slow Poke (>5 seconds)

3. 慢乌龟(超过5秒)

What: Test taking >5 seconds to run
Detection:
  • Measure test duration
  • If >5s → Slow Poke
Severity: MEDIUM
Recommendation: Mock external deps, use in-memory DB, parallelize
Effort: M
定义: 运行时间超过5秒的测试
检测方式:
  • 测量测试运行时长
  • 若超过5秒 → 属于慢乌龟
严重程度:
建议: Mock外部依赖,使用内存数据库,并行化测试
整改工作量: M

4. Conjoined Twins (Unit test without mocks = Integration)

4. 连体双胞胎(无Mock的单元测试=集成测试)

What: Test labeled "Unit" but not mocking dependencies
Detection:
  • Check if test name includes "Unit"
  • Verify all dependencies are mocked
  • If no mocks → actually Integration test
Severity: LOW
Recommendation: Either mock dependencies OR rename to Integration test
Effort: S
定义: 标记为“单元测试”但未Mock依赖的测试
检测方式:
  • 检查测试名称是否包含“Unit”
  • 验证所有依赖是否已Mock
  • 若未使用Mock → 实际为集成测试
严重程度:
建议: 要么Mock依赖,要么重命名为集成测试
整改工作量: S

5. Happy Path Only (No error scenarios)

5. 仅快乐路径(无错误场景)

What: Only testing success cases, ignoring errors
Detection:
  • For each function, check if test covers error cases
  • If only positive scenarios → Happy Path Only
Severity: MEDIUM
Recommendation: Add negative tests (error handling, edge cases)
Effort: M
Example:
  • BAD (Happy Path Only): Test only checks
    login()
    with valid credentials, ignores error scenarios
  • GOOD: Add negative test that verifies
    login()
    with invalid credentials throws 'Invalid credentials' error
定义: 仅测试成功场景,忽略错误情况
检测方式:
  • 针对每个函数,检查测试是否覆盖错误场景
  • 若仅包含正向场景 → 属于仅快乐路径
严重程度:
建议: 添加负面测试(错误处理、边缘情况)
整改工作量: M
示例:
  • 不良实践(仅快乐路径): 测试仅检查有效凭证的
    login()
    ,忽略错误场景
  • 良好实践: 添加负面测试,验证使用无效凭证调用
    login()
    时会抛出'Invalid credentials'错误

6. Framework Tester (Tests framework behavior)

6. 框架测试器(测试框架行为)

What: Tests validating Express/Prisma/bcrypt (NOT our code)
Detection:
  • Already detected by ln-631-test-business-logic-auditor
  • Cross-reference findings
Severity: MEDIUM
Recommendation: Delete framework tests
Effort: S
定义: 验证Express/Prisma/bcrypt的测试(而非我们的代码)
检测方式:
  • 已由ln-631-test-business-logic-auditor检测
  • 交叉引用检测结果
严重程度:
建议: 删除框架测试
整改工作量: S

Scoring Algorithm

评分算法

See
shared/references/audit_scoring.md
for unified formula and score interpretation.
Severity mapping:
  • Flaky tests, External API not mocked, The Liar → HIGH
  • Real database, File system, Time/Date, Network, The Giant, Happy Path Only → MEDIUM
  • Random without seed, Order-dependent, Conjoined Twins → LOW
统一公式及分数解释请参见
shared/references/audit_scoring.md
严重程度映射:
  • 不稳定测试、未Mock外部API、说谎者 → 高
  • 真实数据库、文件系统、时间/日期、网络、巨人、仅快乐路径 → 中
  • 未设置种子的随机数、顺序依赖、连体双胞胎 → 低

Output Format

输出格式

Return JSON to coordinator (flat findings array):
json
{
  "category": "Isolation & Anti-Patterns",
  "score": 6,
  "total_issues": 18,
  "critical": 0,
  "high": 5,
  "medium": 10,
  "low": 3,
  "checks": [
    {"id": "api_isolation", "name": "API Isolation", "status": "failed", "details": "2 tests make real HTTP calls"},
    {"id": "db_isolation", "name": "Database Isolation", "status": "warning", "details": "1 test uses real PostgreSQL"},
    {"id": "fs_isolation", "name": "File System Isolation", "status": "passed", "details": "All FS calls mocked"},
    {"id": "time_isolation", "name": "Time Isolation", "status": "passed", "details": "All Date/Time mocked"},
    {"id": "flaky_tests", "name": "Flaky Tests", "status": "failed", "details": "3 race conditions detected"},
    {"id": "anti_patterns", "name": "Anti-Patterns", "status": "warning", "details": "2 Liars, 1 Giant found"}
  ],
  "findings": [
    {
      "severity": "HIGH",
      "location": "user.test.ts:45-52",
      "issue": "External API not mocked — test makes real HTTP call to https://api.github.com",
      "principle": "Test Isolation / External APIs",
      "recommendation": "Mock external API with nock or jest.mock",
      "effort": "M"
    },
    {
      "severity": "HIGH",
      "location": "async.test.ts:28-35",
      "issue": "Flaky test (race condition) — setTimeout without proper await",
      "principle": "Determinism / Race Condition",
      "recommendation": "Fix race condition with proper async/await",
      "effort": "M"
    },
    {
      "severity": "HIGH",
      "location": "user.test.ts:45",
      "issue": "Anti-pattern 'The Liar' — test 'createUser works' has no assertions",
      "principle": "Anti-Patterns / The Liar",
      "recommendation": "Add specific assertions or delete test",
      "effort": "S"
    },
    {
      "severity": "MEDIUM",
      "location": "db.test.ts:12",
      "issue": "Real database used — test connects to localhost:5432 PostgreSQL",
      "principle": "Test Isolation / Database",
      "recommendation": "Use in-memory SQLite (:memory:) or mock DB",
      "effort": "L"
    },
    {
      "severity": "MEDIUM",
      "location": "order.test.ts:200-350",
      "issue": "Anti-pattern 'The Giant' — test 'order flow' is 150 lines (>100)",
      "principle": "Anti-Patterns / The Giant",
      "recommendation": "Split into focused tests (one scenario per test)",
      "effort": "M"
    },
    {
      "severity": "MEDIUM",
      "location": "payment.test.ts",
      "issue": "Anti-pattern 'Happy Path Only' — only success scenarios, no error tests",
      "principle": "Anti-Patterns / Happy Path Only",
      "recommendation": "Add negative tests for error handling",
      "effort": "M"
    }
  ]
}
Note: Findings are flattened into single array. Use
principle
field prefix (Test Isolation / Determinism / Anti-Patterns) to identify issue category.
向协调器返回JSON(扁平化结果数组):
json
{
  "category": "Isolation & Anti-Patterns",
  "score": 6,
  "total_issues": 18,
  "critical": 0,
  "high": 5,
  "medium": 10,
  "low": 3,
  "checks": [
    {"id": "api_isolation", "name": "API Isolation", "status": "failed", "details": "2 tests make real HTTP calls"},
    {"id": "db_isolation", "name": "Database Isolation", "status": "warning", "details": "1 test uses real PostgreSQL"},
    {"id": "fs_isolation", "name": "File System Isolation", "status": "passed", "details": "All FS calls mocked"},
    {"id": "time_isolation", "name": "Time Isolation", "status": "passed", "details": "All Date/Time mocked"},
    {"id": "flaky_tests", "name": "Flaky Tests", "status": "failed", "details": "3 race conditions detected"},
    {"id": "anti_patterns", "name": "Anti-Patterns", "status": "warning", "details": "2 Liars, 1 Giant found"}
  ],
  "findings": [
    {
      "severity": "HIGH",
      "location": "user.test.ts:45-52",
      "issue": "External API not mocked — test makes real HTTP call to https://api.github.com",
      "principle": "Test Isolation / External APIs",
      "recommendation": "Mock external API with nock or jest.mock",
      "effort": "M"
    },
    {
      "severity": "HIGH",
      "location": "async.test.ts:28-35",
      "issue": "Flaky test (race condition) — setTimeout without proper await",
      "principle": "Determinism / Race Condition",
      "recommendation": "Fix race condition with proper async/await",
      "effort": "M"
    },
    {
      "severity": "HIGH",
      "location": "user.test.ts:45",
      "issue": "Anti-pattern 'The Liar' — test 'createUser works' has no assertions",
      "principle": "Anti-Patterns / The Liar",
      "recommendation": "Add specific assertions or delete test",
      "effort": "S"
    },
    {
      "severity": "MEDIUM",
      "location": "db.test.ts:12",
      "issue": "Real database used — test connects to localhost:5432 PostgreSQL",
      "principle": "Test Isolation / Database",
      "recommendation": "Use in-memory SQLite (:memory:) or mock DB",
      "effort": "L"
    },
    {
      "severity": "MEDIUM",
      "location": "order.test.ts:200-350",
      "issue": "Anti-pattern 'The Giant' — test 'order flow' is 150 lines (>100)",
      "principle": "Anti-Patterns / The Giant",
      "recommendation": "Split into focused tests (one scenario per test)",
      "effort": "M"
    },
    {
      "severity": "MEDIUM",
      "location": "payment.test.ts",
      "issue": "Anti-pattern 'Happy Path Only' — only success scenarios, no error tests",
      "principle": "Anti-Patterns / Happy Path Only",
      "recommendation": "Add negative tests for error handling",
      "effort": "M"
    }
  ]
}
注意: 结果被扁平化为单个数组。使用
principle
字段前缀(测试隔离/确定性/反模式)识别问题类别。

Reference Files

参考文件

  • Audit scoring formula:
    shared/references/audit_scoring.md
  • Audit output schema:
    shared/references/audit_output_schema.md

Version: 3.0.0 Last Updated: 2025-12-23
  • 审计评分公式:
    shared/references/audit_scoring.md
  • 审计输出 schema:
    shared/references/audit_output_schema.md

版本: 3.0.0 最后更新: 2025-12-23