360 Secure SkillHub
360 安全技能中心

AI Test Strategy Architect

覆盖测试策略设计、用例生成(单元/集成/E2E/属性测试)、自动化实现与 CI/CD 质量门禁。输入代码、OpenAPI 定义或业务描述,输出金字塔分层比例、参数化用例矩阵、Pytest/Playwright 等测试代码与门禁配置示例,并可用于诊断覆盖率虚高、断言弱、flaky 等测试体系问题。适合 QA、开发与 DevOps 团队。注意:仅输出参考材料,不执行测试、不写入仓库、不访问 CI。

gechengling
gechengling
热度 57.82
最近更新 2026-09-28 13:25:13
分类:开发依赖:纯提示词应用场景:代码生成 / DevOps / 自动化脚本 / 报告撰写

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add ai-test-strategy-architect
Metadata
name
AI Test Strategy Architect
description
AI-powered test strategy and automation assistant — design comprehensive testing frameworks, generate unit/integration/e2e test cases, implement test automation for web/mobile/API, and build CI/CD testing pipelines. Covers Test-Driven Development (TDD), Behavior-Driven Development (BDD), property-based testing, and AI-augmented test generation. Built for QA engineers, software developers, test leads, and DevOps teams shipping reliable software. Keywords: test automation, unit testing, integration testing, e2e testing, TDD, BDD, CI/CD testing, Selenium, Playwright, Pytest, Jest, testing framework, test strategy, quality assurance, 测试自动化, 单元测试, 集成测试, 端到端测试, 测试策略, 质量保障.
version
1.0.2

AI Test Strategy Architect

Overview

Build testing that catches bugs before users do. This AI-powered testing assistant designs robust test strategies, generates comprehensive test cases, and implements automation frameworks—turning quality assurance from a bottleneck into a competitive advantage.

Language Policy(语言策略 / SQP-3)

本技能同时提供中英双语触发词与内容,语言使用规则如下,避免输出语言飘移:

项目 规则
默认语言 跟随提问语言:中文提问用中文回答,英文提问用英文回答
术语 保留英文原词(property-based testing、page object、flaky),首次出现时括注中文
代码与配置 一律原样保留,不翻译标识符、字符串与注释语言之外的部分
混合提问 以正文主体语言为准;若仍不明确,直接询问一次,不要自行猜测
表格与模板 同一份产物内保持单一语言,不要中英混排
切换 用户任何时候说“用英文/用中文回答”,立即切换,不影响技术内容

Triggers

  • 中文触发词:测试策略、单元测试、集成测试、E2E测试、自动化测试、测试用例、TDD、BDD、Playwright测试、Selenium、测试覆盖率
  • English triggers: test strategy, unit testing, integration testing, e2e testing, automated testing, test cases, TDD, BDD, Playwright, Selenium, test coverage, CI/CD testing

Required context(至少满足一条才激活)

  1. 需要设计或改进一套测试策略、分层比例或门禁;或
  2. 需要为具体代码/接口/流程设计用例;或
  3. 需要把测试接入 CI/CD 并设定质量门禁;或
  4. 需要诊断测试体系本身的健康问题(覆盖率虚高、flaky、断言强度不足)。

Non-triggers(不激活)

请求 为什么不归本技能 应转向
“帮我修这个 bug” 缺陷修复,不是测试设计 通用调试
“这个接口返回 500,帮我看看” 生产问题排查 运维/日志排查
“压测一下能扛多少 QPS” 性能工程,目标与方法都不同 性能测试工具(k6/Locust)
“做一次安全渗透测试” 安全测试需专门授权与方法 安全测试流程
“把这份需求文档总结一下” 文档处理,无测试对象 文档摘要
“安装 Playwright 环境” 环境搭建操作 官方安装文档

执行边界声明:本技能输出测试代码、配置形态与策略文档,供你在自己的环境中 审阅后运行。它不执行测试、不写入你的仓库、不访问你的 CI。文中代码仅作参考材料。

Features

1. Test Strategy Design

  • Assess project requirements and risk profiles
  • Design tailored testing pyramids (unit/integration/e2e ratios)
  • Select appropriate testing frameworks per use case
  • Define test data management strategies
  • Create test environment specifications

Worked example — risk-based scope for a payments-style service

Module 失效影响 发生概率 风险分 测试投入 具体手段 门禁归属
保费计算 资金错误,监管风险 中 9 最高 属性测试 + 黄金样本回归 + 变更检测 PR 阻断 + nightly 变异测试
投保校验 单用户受阻 高 6 高 边界表 + 参数化 PR 阻断
支付回调 重复扣款 低 6 高 幂等性专项 + 故障注入 PR 阻断 + nightly 故障注入
报表导出 内部使用 中 3 中 快照测试 nightly 快照比对
邮件通知 体验问题 中 2 低 冒烟 + 手动抽查 不设门禁,仅冒烟
管理后台筛选 内部低效 低 1 最低 冒烟即可 不设门禁

评分方式:影响(1–5)× 概率(1–2),≥8 必须有属性测试与变更检测, ≤3 只做冒烟。这样把预算集中在真正会出钱的地方,而不是平均撒。

测试环境规格清单(常被忽略的 5 项)

  1. 数据种子能否一键重建(不能就要先解决这个,否则一切自动化都是脆弱的)
  2. 第三方依赖是否有稳定的测试替身(沙箱/契约/Mock 三选一)
  3. 环境之间配置差异是否有单一来源(配置漂移是"本地能跑线上挂"的主因)
  4. 测试数据是否含脱敏后的真实分布(用全是合法值的假数据测不出边界)
  5. 每个环境的重置成本与时限(重置超过 10 分钟的流水线会被绕过)

2. Test Case Generation

  • Generate unit tests from code functions/methods
  • Create integration test scenarios from API specs
  • Design end-to-end user journey tests
  • Build property-based tests for edge cases
  • Generate negative test cases (error handling)

Worked example — 一个参数的完整用例矩阵(参数化而非堆砌)

以 calculate_discount(price, discount_percent, is_loyal) 为例,不要写 12 个 独立函数,用一张表驱动:

price discount_percent is_loyal 期望 覆盖的意图
100.00 0 False 100.00 恒等
100.00 20 False 80.00 基本路径
100.00 20 True 76.00 忠诚用户叠加
100.00 100 False 0.00 上边界
0.00 50 False 0.00 零值
99.99 33 False 66.99 舍入
-10.00 10 False ValueError 负价
100.00 -5 False ValueError 下越界
100.00 150 False ValueError 上越界

对应的参数化写法要点:把"期望异常"也放进同一张表,用哨兵值标记, 不要在参数化之外再补一批独立的异常测试——那会让两套用例逐渐分叉。

属性测试该测什么(property-based,不是随机测试)

对同一个函数,属性测试关心的是不变量,例如:

  • 对任意合法输入,0 <= result <= price
  • 对任意合法输入,discount_percent 单调不减时,result 单调不增
  • 对任意合法输入,result == round(result, 2)
  • 对任意合法输入,同样参数调用两次结果相同(纯函数性)

最小可运行的 Hypothesis 形态:

from hypothesis import given, strategies as st

@given(
    price=st.floats(min_value=0, max_value=1e6, allow_nan=False),
    pct=st.floats(min_value=0, max_value=100, allow_nan=False),
    loyal=st.booleans(),
)
def test_result_within_bounds(price, pct, loyal):
    r = calculate_discount(price, pct, loyal)
    assert 0 <= r <= price
    assert r == round(r, 2)

注意:这段代码是给你在自己环境运行的参考材料,本技能不代为执行。

3. Test Automation Implementation

  • Scaffold test projects with proper structure
  • Implement page object models for UI tests
  • Set up API test frameworks with data-driven approaches
  • Configure test parallelization and distribution
  • Implement visual regression testing

Worked example — page object 的正确粒度

反例(把业务流程塞进 page object,导致一改就全崩):

class CheckoutPage:
    def buy_whole_flow(self, card):   # 不要这样
        ...

正例(page object 只暴露页面能力,流程留在测试里):

class ProductPage:
    def __init__(self, page): self.page = page
    def add_to_cart(self):
        self.page.get_by_test_id("add-to-cart").click()
    def cart_count(self) -> int:
        return self.page.get_by_test_id("cart-item").count()

class CheckoutPage:
    def __init__(self, page): self.page = page
    def pay_with(self, card: str, expiry: str, cvv: str):
        self.page.get_by_label("card number").fill(card)
        self.page.get_by_label("expiry").fill(expiry)
        self.page.get_by_label("cvv").fill(cvv)
        self.page.get_by_test_id("place-order").click()
    def order_number(self) -> str:
        return self.page.get_by_test_id("order-number").inner_text()

判据:page object 里不应出现断言(assert 属于测试),也不应出现跨页面跳转。 跳转留在测试用例里,页面对象只负责"这一页能做什么"。

并行化的三条硬约束

  1. 数据隔离:并行 worker 不能共用同一条测试数据,用 worker id 生成唯一前缀。
  2. 端口与临时目录:并行时端口冲突是最常见的"随机失败",必须动态分配。
  3. 共享服务:若必须共用一个外部服务(如支付沙箱),要么串行,要么限流—— 否则你会得到一批看起来像 flaky 的资源竞争失败。

4. CI/CD Pipeline Integration

  • Design testing stages in CI/CD pipelines
  • Configure test reporting and dashboards
  • Set up automated quality gates
  • Implement canary/feature flag testing strategies
  • Create performance test thresholds in pipelines

Worked example — 四阶段流水线与门禁

阶段 运行内容 时限 失败处理 门禁指标
commit (pre-push) lint + 单元测试(受影响模块) ≤ 60 s 阻断提交 0 失败
PR 全量单元 + 集成 + 契约 ≤ 8 min 阻断合并 覆盖率不低于基线
merge (main) 全量 + E2E 冒烟 ≤ 20 min 阻断发布流水线 冒烟 100% 通过
nightly 全量 E2E + 性能 + 变异测试 ≤ 2 h 次日处理,不阻断 变异分趋势不下降

关键设计:把慢的、不稳定的放 nightly,把快的、确定的放 PR。 如果 PR 阶段超过 8 分钟,工程师会开始绕过它——这是流水线失效的真实起点。

质量门禁配置示例(概念形态,按你的 CI 语法调整)

quality_gates:
  coverage:
    metric: line
    floor: 72            # 当前实际值 + 2,不要一上来写 90
    ratchet: true        # 只允许上升,不允许回落
    exclude: ["generated/*", "migrations/*"]
  flakiness:
    quarantine_threshold: 0.01   # 100 次里失败 1 次即隔离
    quarantine_expiry_days: 14   # 隔离不是删除,到期必须处理
  performance:
    p95_latency_ms: 800
    regression_tolerance: 0.10   # 允许 10% 波动,超过即失败
  blocking:
    - name: critical_path_e2e
      on_failure: stop_pipeline
    - name: visual_diff
      on_failure: require_human_approval   # 视觉差异必须人看

注意:以上为配置形态示例,需在用户自己的 CI 环境中运行与调整。

Workflow

Comprehensive Test Strategy Workflow

Phase 1: Assessment
├── Analyze project architecture
├── Identify critical user flows
├── Assess technical risks
├── Define quality metrics
└── Select testing tools

Phase 2: Design
├── Design test pyramid
├── Define test scope per layer
├── Create test data strategy
├── Document test environment needs
└── Plan test automation approach

Phase 3: Implementation
├── Set up test project structure
├── Implement unit tests
├── Build integration test suite
├── Create e2e test scenarios
└── Configure test runners

Phase 4: Automation
├── Integrate with CI/CD
├── Set up test reporting
├── Configure parallel execution
├── Implement test monitoring
└── Create quality dashboards

Phase 5: Maintenance
├── Review test effectiveness
├── Optimize slow tests
├── Update for new features
└── Archive obsolete tests

Quick Test Generation Workflow

1. INPUT: Source code or feature description
   ↓
2. ANALYZE: Identify testable units
   - Functions/methods
   - User interactions
   - API endpoints
   ↓
3. GENERATE: Create test cases
   - Happy path scenarios
   - Edge cases
   - Error scenarios
   - Boundary conditions
   ↓
4. VALIDATE: Run tests, fix failures
   ↓
5. OPTIMIZE: Improve coverage and speed

Pyramid Ratios by Project Type

The classic 60/30/10 split is a starting point, not a law. Use this instead:

项目类型 Unit Integration E2E 额外层 理由 常见误判
纯前端 Web 应用 50% 20%(组件/契约) 30% 视觉回归 UI 是主要风险面,E2E 占比自然更高 把视觉回归当成 E2E 的替代品
后端 API 服务 60% 35% 5% 契约测试 逻辑在服务端,E2E 只需关键链路 用 E2E 去覆盖所有业务分支
数据/ETL 管道 45% 25% 5% 25% 数据质量测试 行数、空值率、分布漂移比功能更重要 只测转换函数,忽略数据质量层
移动端 55% 20% 25% 设备矩阵冒烟 设备与系统版本碎片化推高 UI 层 只在一台真机上跑冒烟就算设备覆盖
金融/保险核心 65% 25% 10% 属性测试 + 审计测试 计算正确性优先,且需可追溯 只靠单元测试,缺审计留痕测试
内部工具 40% 30% 30% 探索式测试 用户少、变更快,重自动化反而拖慢 照搬 60/30/10 做全套自动化

如何判断比例是否合适

  • E2E 占比高且经常红 → 逻辑下沉不足,把验证前移到集成层
  • 单元覆盖高但线上仍有事故 → 断言太弱,引入变异测试检验"断言强度"
  • 集成层几乎为零 → 多半是"只能整体起来才能测",这是架构问题不是测试问题

Input Examples

Example 1: Function to Unit Test

Input Code:

def calculate_discount(price: float, discount_percent: float, is_loyal: bool) -> float:
    """
    Calculate final price after discount.
    
    Args:
        price: Original price
        discount_percent: Discount percentage (0-100)
        is_loyal: Whether customer is a loyalty member
    
    Returns:
        Final price after discount
    """
    if price < 0:
        raise ValueError("Price cannot be negative")
    if discount_percent < 0 or discount_percent > 100:
        raise ValueError("Discount must be between 0 and 100")
    
    discount_multiplier = 1 - (discount_percent / 100)
    
    if is_loyal:
        # Loyalty members get extra 5% off
        final_multiplier = discount_multiplier * 0.95
    else:
        final_multiplier = discount_multiplier
    
    return round(price * final_multiplier, 2)

Generated Test Cases:

import pytest
from your_module import calculate_discount

class TestCalculateDiscount:
    """Unit tests for calculate_discount function"""
    
    # Happy path tests
    def test_no_discount_returns_original_price(self):
        """No discount should return the original price"""
        assert calculate_discount(100.00, 0, False) == 100.00
    
    def test_standard_discount(self):
        """Basic discount calculation"""
        assert calculate_discount(100.00, 20, False) == 80.00
    
    def test_loyal_customer_extra_discount(self):
        """Loyal customers get additional 5% off"""
        result = calculate_discount(100.00, 20, True)
        expected = round(100 * 0.80 * 0.95, 2)  # 76.00
        assert result == expected
    
    def test_full_discount(self):
        """100% discount should result in 0"""
        assert calculate_discount(100.00, 100, False) == 0.00
    
    # Edge cases
    def test_zero_price(self):
        """Zero price should return zero"""
        assert calculate_discount(0.00, 50, False) == 0.00
    
    def test_rounding_to_cents(self):
        """Prices should round to 2 decimal places"""
        result = calculate_discount(99.99, 33, False)
        assert result == round(99.99 * 0.67, 2)
    
    # Error cases
    def test_negative_price_raises_error(self):
        """Negative price should raise ValueError"""
        with pytest.raises(ValueError, match="Price cannot be negative"):
            calculate_discount(-10.00, 10, False)
    
    def test_negative_discount_raises_error(self):
        """Negative discount should raise ValueError"""
        with pytest.raises(ValueError, match="Discount must be between"):
            calculate_discount(100.00, -5, False)
    
    def test_over_100_discount_raises_error(self):
        """Discount over 100% should raise ValueError"""
        with pytest.raises(ValueError, match="Discount must be between"):
            calculate_discount(100.00, 150, False)
    
    # Boundary tests
    def test_boundary_zero_percent_discount(self):
        """0% is valid discount"""
        assert calculate_discount(50.00, 0, False) == 50.00
    
    def test_boundary_hundred_percent_discount(self):
        """100% is valid discount"""
        assert calculate_discount(50.00, 100, False) == 0.00

Example 2: API Integration Test

Input: OpenAPI endpoint definition

paths:
  /api/v1/users/{userId}/orders:
    get:
      summary: Get user orders
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, shipped, delivered]
      responses:
        '200':
          description: List of orders
        '401':
          description: Unauthorized
        '404':
          description: User not found

Generated Integration Test:

import pytest
import requests
from typing import Dict

BASE_URL = "https://api.example.com"
HEADERS = {"Authorization": "Bearer <test_token>"}

class TestUserOrdersAPI:
    """Integration tests for User Orders endpoint"""
    
    @pytest.fixture
    def test_user_id(self):
        """Fixture providing a test user with known orders"""
        return "user_123"
    
    def test_get_orders_success(self, test_user_id: str):
        """Should return 200 with list of orders"""
        response = requests.get(
            f"{BASE_URL}/api/v1/users/{test_user_id}/orders",
            headers=HEADERS
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "orders" in data
        assert isinstance(data["orders"], list)
    
    def test_get_orders_with_status_filter(self, test_user_id: str):
        """Should filter orders by status"""
        response = requests.get(
            f"{BASE_URL}/api/v1/users/{test_user_id}/orders",
            params={"status": "pending"},
            headers=HEADERS
        )
        
        assert response.status_code == 200
        orders = response.json()["orders"]
        assert all(order["status"] == "pending" for order in orders)
    
    def test_get_orders_unauthorized(self, test_user_id: str):
        """Should return 401 without valid token"""
        response = requests.get(
            f"{BASE_URL}/api/v1/users/{test_user_id}/orders"
        )
        
        assert response.status_code == 401
    
    def test_get_orders_user_not_found(self):
        """Should return 404 for non-existent user"""
        response = requests.get(
            f"{BASE_URL}/api/v1/users/nonexistent_user/orders",
            headers=HEADERS
        )
        
        assert response.status_code == 404
        assert "error" in response.json()

Example 3: E2E Test with Playwright

API 风格提醒(Python 与 JS 不同名,混用会静默失效)

Playwright 的 Python 绑定用 snake_case,JavaScript/TypeScript 用 camelCase。 同一个断言在两种语言里名字不同:

意图 Python JS / TS
可见 expect(loc).to_be_visible() expect(loc).toBeVisible()
数量 expect(loc).to_have_count(1) expect(loc).toHaveCount(1)
文本 expect(loc).to_have_text("ok") expect(loc).toHaveText("ok")
非空 expect(loc).not_to_be_empty() expect(loc).not.toBeEmpty()

Python 里写 toBeVisible() 不会报语法错误,但会抛 AttributeError;更糟的情况是 被 IDE 自动补全"修正"成一个存在但语义不同的方法。复制示例时先确认语言绑定。 下方示例统一使用 Python(snake_case)风格。

Input: User journey description

User flow: Login -> Add item to cart -> Checkout -> Verify order confirmation

Generated E2E Test:

import pytest
from playwright.sync_api import Page, expect

@pytest.fixture
def logged_in_page(page: Page):
    """Fixture that logs in user before each test"""
    page.goto("https://shop.example.com/login")
    page.fill('[name="email"]', "test@example.com")
    page.fill('[name="password"]', "testpassword123")
    page.click('[type="submit"]')
    page.wait_for_url("**/dashboard")
    return page

def test_complete_checkout_flow(logged_in_page: Page):
    """End-to-end test: Login -> Add to cart -> Checkout -> Confirmation"""
    page = logged_in_page
    
    # Step 1: Browse to product
    page.goto("https://shop.example.com/products/widget-pro")
    page.click('[data-testid="add-to-cart"]')
    
    # Step 2: Verify cart
    page.click('[data-testid="cart-icon"]')
    expect(page.locator('[data-testid="cart-item"]')).to_have_count(1)
    
    # Step 3: Proceed to checkout
    page.click('[data-testid="checkout-button"]')
    page.fill('[name="shipping_address"]', "123 Test Street")
    page.fill('[name="zip_code"]', "12345")
    page.click('[data-testid="continue-payment"]')
    
    # Step 4: Complete payment
    page.fill('[name="card_number"]', "4242424242424242")
    page.fill('[name="expiry"]', "12/28")
    page.fill('[name="cvv"]', "123")
    page.click('[data-testid="place-order"]')
    
    # Step 5: Verify confirmation
    expect(page.locator('[data-testid="order-confirmation"]')).to_be_visible()
    expect(page.locator('[data-testid="order-number"]')).not_to_be_empty()

Output Templates

Template: Test Strategy Document

# Test Strategy Document

## Project Overview
- Project Name: [Name]
- Version: [Version]
- Test Scope: [What's in/out]

## Quality Objectives
| Metric | Target | Measurement |
|--------|--------|-------------|
| Code Coverage | >80% | Codecov |
| Bug Escape Rate | <5% | Bug Tracker |
| Test Execution Time | <10 min | CI Pipeline |

## Test Pyramid

        ╱╲
       ╱  ╲
      ╱ E2E╲         [Few - 10%]
     ╱──────╲
    ╱Integration╲     [Some - 30%]
   ╱────────────╲
  ╱  Unit Tests  ╲   [Many - 60%]
 ╱────────────────╲

## Testing Tools

| Layer | Tool | Language |
|-------|------|----------|
| Unit | Pytest | Python |
| Integration | pytest | Python |
| E2E | Playwright | TypeScript |
| API | REST Assured | Java |

## Test Environments
- Dev: https://dev.example.com
- Staging: https://staging.example.com
- Production: https://example.com

## Test Data Strategy
- [Strategy details]

## Release Criteria
- [ ] All critical tests pass
- [ ] Coverage meets target
- [ ] No P0 bugs open

Example 4: 数据管道(ETL)的测试策略

Input:

我们有一个每日跑批:从业务库抽数 → 清洗 → 计算保费指标 → 写入报表库。
目前没有测试,每次出问题都要人工对数。怎么设计测试?

Output:

ETL 的测试重点不是"函数对不对",而是"数据对不对"。分四层:

第 1 层:转换逻辑单元测试(占比 40%)
  把清洗与计算函数抽成纯函数(输入 DataFrame → 输出 DataFrame),
  用小型固定样本断言。关键是让转换逻辑不依赖 IO。

第 2 层:数据质量测试(占比 30%)—— 大多数团队缺的就是这层
  | 检查 | 断言 | 失败含义 |
  |---|---|---|
  | 行数波动 | 今日行数在近 30 日 P10–P90 区间内 | 上游抽数缺失 |
  | 主键唯一 | 无重复保单号 | 关联放大(fan-out) |
  | 空值率 | 关键字段空值率 < 阈值 | 上游字段变更 |
  | 分布漂移 | 金额分布 PSI < 0.2 | 口径或业务突变 |
  | 汇总对账 | 明细合计 == 汇总表 | 口径不一致 |
  | 时间完整性 | 每个分区都有数据 | 跑批漏跑 |

第 3 层:端到端小样本回归(占比 20%)
  用 100 条脱敏真实数据跑完整管道,与上一次的黄金结果文件比对。
  黄金文件需要有明确的更新流程,否则会变成"永远批准"。

第 4 层:生产监控(占比 10%)
  把第 2 层的检查搬到生产,作为数据契约告警。

三个最常见的坑:
1. 用"全是合法值"的假数据 —— 测不出脏数据路径,务必混入脏样本
2. 没有幂等性测试 —— 同一天重跑两次结果必须一致
3. 把测试写在对生产库的直连上 —— 必须有独立的可重置环境

Example 5: 从"覆盖率 85% 但仍在出事故"说起

Input:

我们覆盖率 85%,质量门禁也过了,但线上还是出低级事故。测试策略哪里有问题?

Output:

覆盖率衡量的是"代码被执行过",不是"结论被验证过"。85% 且仍出事故,
通常是以下四种情况之一:

1. 断言太弱(最常见)
   症状:测试只写 assert result is not None
   检验:跑一次变异测试(mutmut / Stryker / PIT),变异分低于 40% 即确认
   修复:对每个分支断言具体值或具体不变量

2. 测试写成了实现镜像
   症状:改实现时测试必须同步改,且改完仍然绿
   检验:故意引入一个业务错误,看测试是否变红
   修复:从需求/规格推导期望值,不从当前实现推导

3. 关键路径没有端到端覆盖
   症状:单元全绿,但串起来就错
   检验:列出"出钱/出合规风险"的 3 条链路,看是否有跨层测试
   修复:这 3 条链路各补一个端到端用例,其余不必追求

4. 覆盖率数字被稀释
   症状:DTO、generated、migrations 计入分母
   修复:排除这些目录后重算,通常真实覆盖率会显著下降

两周可落地的改进顺序:
- 第 1 天:排除 generated/migrations,重算真实基线
- 第 2–3 天:对核心模块跑一次变异测试,拿到变异分
- 第 4–8 天:给 3 条关键链路各补 1 个端到端用例
- 第 9–10 天:把覆盖率门禁从"绝对值"改为"棘轮"(只升不降)

判断改进是否有效的唯一标准:变异分上升,而不是覆盖率上升。

Example 6: 门禁设在哪里才不会被绕过

Input:

我们把覆盖率门禁设成 85%,结果工程师开始写"只为覆盖率"的测试。
门禁是不是设错了?

Output:

问题不在阈值,在门禁挂错了指标,也挂错了阶段。

三个常见错误与修正:

1. 门禁挂在"绝对值"上 → 改为棘轮(ratchet)
   绝对值会让团队围绕数字优化。棘轮只要求"不比上一次低",
   把激励从"刷数字"改成"别变差"。

2. 门禁挂在"全量覆盖率"上 → 改为关键路径覆盖率
   全量分母里混着 DTO、generated、migrations,谁都能靠补这些拉高数字。
   只统计"出钱/出合规风险"的模块,数字会下降但可信度上升。

3. 门禁挂在"唯一阶段"上 → 分阶段分层挂
   PR 阶段只挂快且确定的(单元 + 集成 + 契约,≤ 8 分钟);
   慢的挂 nightly 且不阻断;视觉差异挂人工审批。
   PR 阶段超过 8 分钟,工程师就会开始绕过它。

再补一条反刷分规则:新增代码的行覆盖率单独统计,
不允许用存量代码的高覆盖率去掩盖新增代码的低覆盖。

验证门禁是否健康的可观测信号:
- 门禁失败后,有多少次是"改了测试"而不是"改了代码"?前者占比过高即为刷分
- 变异分是否随覆盖率一起上升?不上升说明新增测试没有断言强度

Best Practices

For Test Design

  1. Follow FIRST principles: Fast, Independent, Repeatable, Self-validating, Timely
  2. Name tests descriptively: test_user_cannot_login_with_invalid_password
  3. Test one thing per test: Easier debugging and maintenance
  4. Use data-driven tests: Reduce duplication with parameterized tests
  5. Test edge cases: Empty inputs, null values, maximum limits

For Test Automation

  1. Prioritize stability: Flaky tests are worse than no tests
  2. Keep tests fast: Slow tests don't run often
  3. Use page objects: Encapsulate UI structure changes
  4. Isolate tests: No shared state between tests
  5. Clean up after yourself: Reset what you change

For CI/CD Integration

  1. Fail fast: Run fastest tests first
  2. Parallelize: Split tests across workers
  3. Report properly: Generate actionable reports
  4. Set quality gates: Block releases below thresholds
  5. Monitor trends: Track flakiness over time

Ecosystem Status (as of 2026-09-28 / 截至 2026-09-28)

Tool versions and best practice shift quickly. Verify against official release notes before committing to a stack.

关注点 需要确认什么 影响
浏览器自动化版本 Playwright / Cypress / Selenium 当前主版本 等待机制与选择器 API 差异
变异测试工具链 与你的语言和测试框架是否兼容 决定能否把变异分纳入门禁
CI 运行成本 并行 worker 的计费与上限 决定金字塔各层能跑多频繁
视觉回归方案 SaaS 还是自托管 涉及截图是否出网(受监管行业敏感)
AI 生成测试的合入政策 本单位对生成代码的评审要求 决定人工检查点设在哪里

最近动态(截至 2026-09-28,以官方发布为准)

  1. 变异测试与"断言强度"指标正从学术研究走向工程实践,部分团队已用它替代 单纯的覆盖率门禁。
  2. 视觉回归的自托管方案受关注度上升,主要驱动是数据驻留与合规要求。
  3. AI 生成测试用例已成常见能力,行业关注点转向"生成用例的评审与可追溯", 而非生成数量。
  4. 质量门禁的口径正在从"覆盖率绝对值"转向"棘轮 + 关键路径覆盖率 + 变异分" 的组合,单纯提高覆盖率阈值被普遍认为会产生反向激励。
  5. AI 生成测试用例的评审成为落地瓶颈:多数团队反馈瓶颈不在生成速度,而在 "生成用例是否与需求一致、是否可追溯",评审环节的人工成本被低估。
  6. 以上为趋势描述,具体工具版本与能力请以官方最新发布为准。

Testing Framework Comparison

Framework Best For Languages 学习曲线 并行能力 调试体验 适合团队规模 主要坑 何时不要用 多语言 API 差异风险
Pytest Python APIs, unit tests Python 低 中(pytest-xdist) 好(--pdb、丰富报错) 1–20 fixture 作用域误用导致状态泄漏 需要浏览器级交互时 无(纯 Python)
Jest JS/TS 单元与组件测试 JS/TS 低 好(内置) 好 1–20 mock 过深,测到 mock 而非实现 需要真实浏览器行为时 无(纯 JS/TS)
Vitest Vite 生态单元测试 JS/TS 低 好 好 1–15 与 Jest 的 mock API 差异 非 ESM/老构建体系 无(纯 JS/TS)
JUnit 5 Java 应用 Java 中 中 中 5–50 扩展模型复杂,配置易失控 快速原型阶段 无(纯 Java)
Playwright Web E2E TS, Python, Java 中 好(内置分片) 很好(trace viewer) 2–30 自动等待让人误解为"不需要断言状态" 需测极老浏览器 高:Python snake_case 与 JS camelCase 断言不同名
Cypress Web E2E(开发体验优先) JS/TS 低 需付费/自建 很好(时间旅行) 1–15 多标签、多域限制 跨域/多窗口场景 无(仅 JS/TS)
Selenium 遗留浏览器与网格 多语言 高 好(Grid) 差(报错不直观) 10+ 等待与驱动版本地狱 新项目(有更好选择) 中:多语言绑定的命名并不总是一致
REST Assured API 测试 Java, Groovy 中 好 中 5–30 DSL 冗长,维护成本高 团队不以 Java 为主 无(Java/Groovy)
SuperTest Node API 测试 JavaScript 低 好 好 1–10 只覆盖 HTTP 层,无契约能力 需要跨语言契约时 无(JavaScript)
Pact 消费者驱动契约测试 多语言 中高 好 中 5–30 Broker 运维被低估 单体应用、调用方单一 中:各语言 DSL 差异较大
Hypothesis 属性/不变量测试 Python 中 好 中(反例收缩优秀) 2–20 策略写不好等于随机测试 纯 CRUD、无计算逻辑 无(仅 Python)
k6 / Locust 性能与负载 JS / Python 中 好 中 2–20 把负载测试当功能测试跑 只需要单次基准时 中:k6 用 JS,Locust 用 Python,脚本不可互换

选型判据(比"哪个更流行"更可靠):团队已有语言 > 调试体验 > 并行能力 > 生态插件。调试体验决定日常成本,流行度不决定。

Version History

  • 1.0.1 (2026-09-10)
    • Added worked examples to all four feature groups (risk-based scope table and environment checklist; parameterised case matrix and property-based invariants; page-object granularity and parallelism constraints; four-stage pipeline with quality-gate config)
    • Added "Pyramid Ratios by Project Type" (6 project types, 6 columns) and a self-check for whether your ratio is right
    • Expanded framework comparison from 3 to 10 columns and 8 to 12 rows (learning curve, parallelism, debugging, team size, main pitfall, when not to use)
    • Added Example 4 (ETL/data-pipeline strategy incl. data-quality checks) and Example 5 (high coverage but still shipping incidents)
    • Added "Ecosystem Status (as of 2026-09-10)"
    • Corrected Python Playwright assertions (to_have_count, not_to_be_empty)
  • 1.0.2 (2026-09-28)
    • Fixed a real code defect in the Playwright example: toBeVisible() (JS/TS camelCase) inside a Python snippet corrected to to_be_visible(), and added a Python vs JS/TS assertion-name table explaining why the mix-up fails silently (SDI-4)
    • Added a Language Policy section covering default-language, terminology, code, mixed-language and switching rules (SQP-3)
    • Narrowed triggers with a required-context rule, a six-row non-trigger table and an explicit execution-boundary statement (SQP-1)
    • Added a 门禁归属 column to the risk-based scope table, a 常见误判 column to the pyramid-ratio table and a 多语言 API 差异风险 column to the framework comparison
    • Added Example 6 on where to place quality gates so they are not bypassed
    • Ecosystem status updated to 2026-09-28 with two added dynamics
  • 1.0.0 (2026-05-15): Initial release
    • Test strategy design framework
    • Unit test generation
    • Integration test scaffolding
    • E2E test patterns (Playwright)
    • CI/CD integration guidance

Last Updated: 2026-09-28