testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Testing

测试

This skill enables an AI agent to systematically generate, run, and evaluate tests for a given codebase. It covers the full testing lifecycle — from analyzing source code and identifying meaningful test cases, through writing and executing tests, to measuring coverage and recommending improvements. The agent supports unit tests, integration tests, and end-to-end tests across multiple languages and frameworks.
此技能使AI Agent能够系统地为给定代码库生成、运行和评估测试。它覆盖完整的测试生命周期——从分析源代码、确定有意义的测试用例,到编写和执行测试,再到衡量覆盖率并提出改进建议。该Agent支持多种语言和框架下的单元测试、集成测试和端到端测试。

Workflow

工作流程

  1. Analyze the source code. Read the target file or module and build a dependency graph of its functions, classes, and external interactions. Identify public interfaces, internal helpers, input parameters, return types, and side effects. This step determines what is testable and what kinds of tests are appropriate.
  2. Identify test cases. For each function or method, enumerate the scenarios that need coverage: happy-path inputs, boundary values, invalid or null inputs, exception paths, and state transitions. For integration points, identify the collaborators that need to be mocked or stubbed versus tested live. Prioritize cases by risk — complex branching logic and public API surfaces come first.
  3. Write the tests. Generate well-structured test code using the project's existing test framework (e.g., pytest, Jest, JUnit). Each test should have a descriptive name that states the scenario and expected outcome. Use the Arrange-Act-Assert pattern: set up preconditions, invoke the code under test, and assert the expected result. Add parameterized tests where a single logical case applies to multiple input sets.
  4. Run the tests. Execute the test suite using the appropriate runner command. Capture the full output including pass/fail status, assertion messages, and timing information. If any tests fail, parse the failure output to determine whether the failure indicates a bug in the source code or an error in the test itself.
  5. Analyze coverage. Run the test suite with coverage instrumentation enabled (e.g.,
    pytest --cov
    ,
    jest --coverage
    ). Parse the coverage report to identify uncovered lines, branches, and functions. Flag any critical code paths — error handlers, security checks, data validation — that lack coverage.
  6. Suggest improvements. Based on coverage gaps and code complexity, recommend additional test cases. Suggest refactoring opportunities that would make the code more testable, such as extracting pure functions or introducing dependency injection. Provide a summary report with coverage percentages and a prioritized list of next actions.
  1. 分析源代码:读取目标文件或模块,构建其函数、类和外部交互的依赖图。识别公共接口、内部辅助函数、输入参数、返回类型和副作用。此步骤确定可测试内容以及适合的测试类型。
  2. 确定测试用例:针对每个函数或方法,列举需要覆盖的场景:正常路径输入、边界值、无效或空输入、异常路径以及状态转换。对于集成点,确定需要模拟/存根还是实际测试的协作对象。按风险优先级排序——复杂分支逻辑和公共API表面优先。
  3. 编写测试:使用项目现有的测试框架(如pytest、Jest、JUnit)生成结构良好的测试代码。每个测试应有描述性名称,说明场景和预期结果。采用Arrange-Act-Assert模式:设置前置条件、调用被测代码、断言预期结果。当单一逻辑适用于多组输入时,添加参数化测试。
  4. 运行测试:使用适当的运行器命令执行测试套件。捕获完整输出,包括通过/失败状态、断言消息和计时信息。如果有测试失败,解析失败输出以确定失败是表明源代码存在bug还是测试本身有误。
  5. 分析覆盖率:启用覆盖率工具执行测试套件(如
    pytest --cov
    jest --coverage
    )。解析覆盖率报告以识别未覆盖的代码行、分支和函数。标记任何缺乏覆盖的关键代码路径——错误处理程序、安全检查、数据验证。
  6. 提出改进建议:基于覆盖率缺口和代码复杂度,推荐额外的测试用例。建议使代码更易于测试的重构机会,例如提取纯函数或引入依赖注入。提供包含覆盖率百分比和优先行动列表的总结报告。

Supported Languages

支持的语言

LanguageFrameworkRunner Command
Pythonpytest
pytest --cov=src -v
JavaScriptJest
npx jest --coverage --verbose
TypeScriptJest / Vitest
npx vitest run --coverage
JavaJUnit 5
mvn test
Gotesting (stdlib)
go test -cover ./...
Rustcargo test
cargo test
语言框架运行器命令
Pythonpytest
pytest --cov=src -v
JavaScriptJest
npx jest --coverage --verbose
TypeScriptJest / Vitest
npx vitest run --coverage
JavaJUnit 5
mvn test
Gotesting (stdlib)
go test -cover ./...
Rustcargo test
cargo test

Usage

使用方法

Provide one or more of the following inputs:
  • Source file or directory to generate tests for (e.g.,
    src/utils/parser.py
    ).
  • Existing test file if you want the agent to extend or improve current tests.
  • Test framework preference if the project does not already have one configured.
  • Coverage threshold if you want the agent to target a specific percentage (e.g., 90%).
提供以下一项或多项输入:
  • 要生成测试的源文件或目录(例如
    src/utils/parser.py
    )。
  • 现有测试文件(如果希望Agent扩展或改进当前测试)。
  • 测试框架偏好(如果项目尚未配置测试框架)。
  • 覆盖率阈值(如果希望Agent以特定百分比为目标,例如90%)。

Examples

示例

Example 1 — Python with pytest

示例1 — 使用pytest的Python

Given this source file
src/cart.py
:
python
class ShoppingCart:
    def __init__(self):
        self.items = []

    def add_item(self, name: str, price: float, quantity: int = 1):
        if price < 0:
            raise ValueError("Price cannot be negative")
        if quantity < 1:
            raise ValueError("Quantity must be at least 1")
        self.items.append({"name": name, "price": price, "quantity": quantity})

    def total(self) -> float:
        return sum(item["price"] * item["quantity"] for item in self.items)

    def remove_item(self, name: str):
        self.items = [item for item in self.items if item["name"] != name]
The agent generates
tests/test_cart.py
:
python
import pytest
from src.cart import ShoppingCart

@pytest.fixture
def cart():
    return ShoppingCart()

def test_add_item_and_total(cart):
    cart.add_item("Widget", 9.99, 2)
    assert cart.total() == pytest.approx(19.98)

def test_empty_cart_total_is_zero(cart):
    assert cart.total() == 0.0

def test_add_item_negative_price_raises(cart):
    with pytest.raises(ValueError, match="Price cannot be negative"):
        cart.add_item("Bad", -1.0)

def test_add_item_zero_quantity_raises(cart):
    with pytest.raises(ValueError, match="Quantity must be at least 1"):
        cart.add_item("Bad", 5.0, 0)

def test_remove_item(cart):
    cart.add_item("A", 1.0)
    cart.add_item("B", 2.0)
    cart.remove_item("A")
    assert cart.total() == 2.0

def test_remove_nonexistent_item_does_nothing(cart):
    cart.add_item("A", 1.0)
    cart.remove_item("Z")
    assert cart.total() == 1.0
Run:
pytest tests/test_cart.py --cov=src -v
给定源文件
src/cart.py
python
class ShoppingCart:
    def __init__(self):
        self.items = []

    def add_item(self, name: str, price: float, quantity: int = 1):
        if price < 0:
            raise ValueError("Price cannot be negative")
        if quantity < 1:
            raise ValueError("Quantity must be at least 1")
        self.items.append({"name": name, "price": price, "quantity": quantity})

    def total(self) -> float:
        return sum(item["price"] * item["quantity"] for item in self.items)

    def remove_item(self, name: str):
        self.items = [item for item in self.items if item["name"] != name]
Agent生成
tests/test_cart.py
python
import pytest
from src.cart import ShoppingCart

@pytest.fixture
def cart():
    return ShoppingCart()

def test_add_item_and_total(cart):
    cart.add_item("Widget", 9.99, 2)
    assert cart.total() == pytest.approx(19.98)

def test_empty_cart_total_is_zero(cart):
    assert cart.total() == 0.0

def test_add_item_negative_price_raises(cart):
    with pytest.raises(ValueError, match="Price cannot be negative"):
        cart.add_item("Bad", -1.0)

def test_add_item_zero_quantity_raises(cart):
    with pytest.raises(ValueError, match="Quantity must be at least 1"):
        cart.add_item("Bad", 5.0, 0)

def test_remove_item(cart):
    cart.add_item("A", 1.0)
    cart.add_item("B", 2.0)
    cart.remove_item("A")
    assert cart.total() == 2.0

def test_remove_nonexistent_item_does_nothing(cart):
    cart.add_item("A", 1.0)
    cart.remove_item("Z")
    assert cart.total() == 1.0
运行:
pytest tests/test_cart.py --cov=src -v

Example 2 — JavaScript with Jest

示例2 — 使用Jest的JavaScript

Given this source file
src/validator.js
:
javascript
function isValidEmail(email) {
  if (typeof email !== "string") return false;
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return re.test(email);
}

function isStrongPassword(password) {
  if (typeof password !== "string") return false;
  return (
    password.length >= 8 &&
    /[A-Z]/.test(password) &&
    /[a-z]/.test(password) &&
    /[0-9]/.test(password)
  );
}

module.exports = { isValidEmail, isStrongPassword };
The agent generates
src/__tests__/validator.test.js
:
javascript
const { isValidEmail, isStrongPassword } = require("../validator");

describe("isValidEmail", () => {
  test.each([
    ["user@example.com", true],
    ["name+tag@sub.domain.org", true],
    ["missing-at-sign.com", false],
    ["@no-local.com", false],
    ["spaces in@email.com", false],
    ["", false],
  ])("isValidEmail(%s) => %s", (input, expected) => {
    expect(isValidEmail(input)).toBe(expected);
  });

  test("returns false for non-string input", () => {
    expect(isValidEmail(null)).toBe(false);
    expect(isValidEmail(42)).toBe(false);
  });
});

describe("isStrongPassword", () => {
  test("accepts a strong password", () => {
    expect(isStrongPassword("Str0ngPwd")).toBe(true);
  });

  test("rejects short password", () => {
    expect(isStrongPassword("Ab1")).toBe(false);
  });

  test("rejects password without uppercase", () => {
    expect(isStrongPassword("alllower1")).toBe(false);
  });

  test("rejects non-string input", () => {
    expect(isStrongPassword(undefined)).toBe(false);
  });
});
Run:
npx jest --coverage --verbose
给定源文件
src/validator.js
javascript
function isValidEmail(email) {
  if (typeof email !== "string") return false;
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return re.test(email);
}

function isStrongPassword(password) {
  if (typeof password !== "string") return false;
  return (
    password.length >= 8 &&
    /[A-Z]/.test(password) &&
    /[a-z]/.test(password) &&
    /[0-9]/.test(password)
  );
}

module.exports = { isValidEmail, isStrongPassword };
Agent生成
src/__tests__/validator.test.js
javascript
const { isValidEmail, isStrongPassword } = require("../validator");

describe("isValidEmail", () => {
  test.each([
    ["user@example.com", true],
    ["name+tag@sub.domain.org", true],
    ["missing-at-sign.com", false],
    ["@no-local.com", false],
    ["spaces in@email.com", false],
    ["", false],
  ])("isValidEmail(%s) => %s", (input, expected) => {
    expect(isValidEmail(input)).toBe(expected);
  });

  test("returns false for non-string input", () => {
    expect(isValidEmail(null)).toBe(false);
    expect(isValidEmail(42)).toBe(false);
  });
});

describe("isStrongPassword", () => {
  test("accepts a strong password", () => {
    expect(isStrongPassword("Str0ngPwd")).toBe(true);
  });

  test("rejects short password", () => {
    expect(isStrongPassword("Ab1")).toBe(false);
  });

  test("rejects password without uppercase", () => {
    expect(isStrongPassword("alllower1")).toBe(false);
  });

  test("rejects non-string input", () => {
    expect(isStrongPassword(undefined)).toBe(false);
  });
});
运行:
npx jest --coverage --verbose

Best Practices

最佳实践

  • Name tests after the scenario, not the implementation. Use names like
    test_empty_cart_total_is_zero
    rather than
    test_total_method
    . This makes failures self-documenting.
  • Keep tests independent. Each test should set up its own state via fixtures or setup methods. Never rely on test execution order.
  • Prefer parameterized tests for input variations. When the same logic applies to many inputs, use
    @pytest.mark.parametrize
    or
    test.each
    instead of duplicating test bodies.
  • Mock external dependencies, not internal logic. Stub network calls, databases, and file I/O. Avoid mocking the code under test itself — that defeats the purpose.
  • Target meaningful coverage, not 100%. Aim for thorough branch coverage of critical paths. Trivial getters and framework-generated code rarely need dedicated tests.
  • Run tests in CI on every commit. Integrate the test command into the project's CI pipeline so regressions are caught immediately.
  • 根据场景而非实现命名测试:使用
    test_empty_cart_total_is_zero
    这样的名称,而非
    test_total_method
    。这能让失败信息自解释。
  • 保持测试独立:每个测试应通过fixture或设置方法建立自己的状态。绝不要依赖测试执行顺序。
  • 对输入变体优先使用参数化测试:当相同逻辑适用于多个输入时,使用
    @pytest.mark.parametrize
    test.each
    而非重复测试代码。
  • 模拟外部依赖而非内部逻辑:存根网络调用、数据库和文件I/O。避免模拟被测代码本身——这违背了测试的目的。
  • 追求有意义的覆盖率,而非100%:针对关键路径实现全面的分支覆盖。琐碎的getter和框架生成的代码很少需要专门测试。
  • 在CI中每次提交都运行测试:将测试命令集成到项目的CI流水线中,以便立即发现回归问题。

Edge Cases

边缘情况

  • Dynamically generated code: If the codebase uses metaprogramming, decorators, or code generation, the agent may not detect all callable paths. Provide hints about generated interfaces.
  • Global state and singletons: Tests for code that mutates global state require careful teardown. The agent will flag these but may need guidance on acceptable reset strategies.
  • Async and concurrent code: Testing async functions requires framework-specific patterns (
    pytest-asyncio
    , Jest's async handling). The agent will use the appropriate pattern but may ask for confirmation on timeout thresholds.
  • Environment-dependent tests: Tests that depend on environment variables, file system layout, or network access should be clearly marked as integration tests and excluded from fast unit-test runs.
  • Flaky tests: If test runs produce intermittent failures, the agent will flag non-deterministic patterns (e.g., reliance on wall-clock time, unordered collection comparisons) and suggest fixes.
  • 动态生成的代码:如果代码库使用元编程、装饰器或代码生成,Agent可能无法检测到所有可调用路径。请提供关于生成接口的提示。
  • 全局状态和单例:测试修改全局状态的代码需要谨慎的清理操作。Agent会标记这些情况,但可能需要关于可接受重置策略的指导。
  • 异步和并发代码:测试异步函数需要特定框架的模式(
    pytest-asyncio
    、Jest的异步处理)。Agent会使用适当的模式,但可能需要确认超时阈值。
  • 依赖环境的测试:依赖环境变量、文件系统布局或网络访问的测试应明确标记为集成测试,并从快速单元测试运行中排除。
  • 不稳定测试:如果测试运行产生间歇性失败,Agent会标记非确定性模式(例如依赖系统时间、无序集合比较)并提出修复建议。