generating-apex-test

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Generating Apex Tests

生成Apex测试

Generate production-ready Apex test classes and run disciplined test-fix loops with coverage analysis.
生成可用于生产环境的Apex测试类,并结合覆盖率分析执行规范的测试修复循环。

Core Principles

核心原则

  1. One behavior per method — each test method validates a single scenario. Separate positive, negative, and bulk tests. NEVER combine related-but-distinct inputs (e.g., null and empty) in one method — create
    _NullInput_
    and
    _EmptyInput_
    as separate test methods
  2. Bulkify tests — test with 251+ records to cross the 200-record trigger batch boundary. Batch Apex exception: in test context only one
    execute()
    invocation runs, so set
    batchSize >= testRecordCount
    . See references/async-testing.md
  3. Isolate test data — every
    @TestSetup
    must delegate record creation to a
    TestDataFactory
    class. If none exists, create one first. Never build record lists inline in
    @TestSetup
    . Never rely on org data (
    SeeAllData=false
    ) or hardcoded IDs. For duplicate rule handling, see references/test-data-factory.md
  4. Assert meaningfully — use exact expected values computed from test data setup. NEVER use range assertions or approximate counts when the value is deterministic. Always include failure messages. See references/assertion-patterns.md
  5. Use
    Assert
    class only
    Assert.areEqual
    ,
    Assert.isTrue
    ,
    Assert.fail
    , etc. Never use legacy
    System.assert
    ,
    System.assertEquals
    , or
    System.assertNotEquals
  6. Mock external boundaries — use
    HttpCalloutMock
    for callouts,
    Test.setFixedSearchResults
    for SOSL, DML mock classes for database isolation. Design for testability via constructor injection. See references/mocking-patterns.md
  7. Test negative paths — validate error handling and exception scenarios, not just happy paths
  8. Wrap with start/stop — pair
    Test.startTest()
    with
    Test.stopTest()
    to reset governor limits and force async execution
  1. 一个方法对应一种行为 —— 每个测试方法仅验证一种场景。将正向、反向和批量测试分开。绝不要在一个方法中组合相关但不同的输入(例如null和空值)—— 应创建
    _NullInput_
    _EmptyInput_
    作为独立的测试方法
  2. 测试批量处理能力 —— 使用251+条记录进行测试,以跨越200条记录的触发器批处理边界。批处理Apex例外情况:在测试环境中仅会运行一次
    execute()
    调用,因此需设置
    batchSize >= testRecordCount
    。详情请参阅references/async-testing.md
  3. 隔离测试数据 —— 每个
    @TestSetup
    都必须将记录创建委托给
    TestDataFactory
    类。如果该类不存在,请先创建。绝不要在
    @TestSetup
    中内联构建记录列表。绝不要依赖组织数据(
    SeeAllData=false
    )或硬编码ID。关于重复规则的处理,请参阅references/test-data-factory.md
  4. 有意义地断言 —— 使用从测试数据设置中计算出的精确预期值。当值是确定的时,绝不要使用范围断言或近似计数。始终包含失败提示信息。详情请参阅references/assertion-patterns.md
  5. 仅使用
    Assert
    —— 使用
    Assert.areEqual
    Assert.isTrue
    Assert.fail
    等方法。绝不要使用旧版的
    System.assert
    System.assertEquals
    System.assertNotEquals
  6. 模拟外部边界 —— 对调用使用
    HttpCalloutMock
    ,对SOSL使用
    Test.setFixedSearchResults
    ,对数据库隔离使用DML模拟类。通过构造函数注入实现可测试性设计。详情请参阅references/mocking-patterns.md
  7. 测试反向路径 —— 验证错误处理和异常场景,而不仅仅是正常路径
  8. 用start/stop包裹 —— 将
    Test.startTest()
    Test.stopTest()
    配对使用,以重置 governor 限制并强制执行异步操作

Test.startTest() / Test.stopTest()

Test.startTest() / Test.stopTest()

Always wrap the code under test in
Test.startTest()
/
Test.stopTest()
:
  • Resets governor limits so the test measures only the code under test
  • Executes async operations synchronously (queueables, batch, future methods)
  • Fires scheduled jobs immediately
始终将被测代码包裹在
Test.startTest()
/
Test.stopTest()
中:
  • 重置 governor 限制,使测试仅测量被测代码的性能
  • 同步执行异步操作(可队列项、批处理、未来方法)
  • 立即触发定时作业

Test Code Anti-Patterns

测试代码反模式

Anti-PatternFix
SOQL/DML inside loopsQuery once before the loop; use
Map<Id, SObject>
for lookups
Magic numbers in assertionsDerive expected values from setup constants
God test class (>500 lines)Split into multiple test classes by behavior area
Long test methods (>30 lines)Extract Given/When/Then into helper methods
Generic
Exception
catch
Catch the specific expected type (e.g.,
DmlException
)
反模式修复方案
循环内的SOQL/DML在循环前查询一次;使用
Map<Id, SObject>
进行查找
断言中的魔术数字从设置常量中推导预期值
上帝测试类(超过500行)按行为领域拆分为多个测试类
长测试方法(超过30行)将Given/When/Then提取到辅助方法中
捕获通用
Exception
捕获特定的预期类型(例如
DmlException

Workflow

工作流程

Step 1 — Gather Context

步骤1 —— 收集上下文

Before generating or fixing tests, identify:
  • the target production class(es) under test
  • existing test classes, test data factories, and setup helpers
  • desired test scope (single class, specific methods, suite, or local tests)
  • coverage threshold (75% minimum for deploy, 90%+ recommended)
  • org alias when running tests against an org
在生成或修复测试之前,确定:
  • 被测的目标生产类
  • 现有的测试类、测试数据工厂和设置辅助工具
  • 所需的测试范围(单个类、特定方法、套件或本地测试)
  • 覆盖率阈值(部署最低要求75%,建议90%+)
  • 针对组织运行测试时的组织别名

Step 2 — Generate the Test Class

步骤2 —— 生成测试类

Apply the structure, naming conventions, and patterns from the asset templates and reference docs.
MANDATORY — File Deliverables: For every test class, create BOTH files:
  1. {ClassName}Test.cls
    — the test class (use assets/test-class-template.cls as starting point)
  2. {ClassName}Test.cls-meta.xml
    — the metadata file:
xml
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>66.0</apiVersion>
    <status>Active</status>
</ApexClass>
If no
TestDataFactory
exists in the project, create
TestDataFactory.cls
+
TestDataFactory.cls-meta.xml
using assets/test-data-factory-template.cls.
应用资产模板和参考文档中的结构、命名约定和模式。
必填 —— 文件交付物: 每个测试类都必须创建以下两个文件:
  1. {ClassName}Test.cls
    —— 测试类(以assets/test-class-template.cls为起点)
  2. {ClassName}Test.cls-meta.xml
    —— 元数据文件:
xml
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>66.0</apiVersion>
    <status>Active</status>
</ApexClass>
如果项目中不存在
TestDataFactory
,请使用assets/test-data-factory-template.cls创建
TestDataFactory.cls
+
TestDataFactory.cls-meta.xml

@TestSetup Example

@TestSetup示例

apex
@TestSetup
static void setupTestData() {
    List<Account> accounts = TestDataFactory.createAccounts(251, true);
}
apex
@TestSetup
static void setupTestData() {
    List<Account> accounts = TestDataFactory.createAccounts(251, true);
}

Test Method Structure

测试方法结构

Use Given/When/Then:
apex
@isTest
static void shouldUpdateStatus_WhenValidInput() {
    // Given
    List<Account> accounts = [SELECT Id FROM Account];

    // When
    Test.startTest();
    MyService.processAccounts(accounts);
    Test.stopTest();

    // Then
    List<Account> updated = [SELECT Id, Status__c FROM Account];
    Assert.areEqual(251, updated.size(), 'All accounts should be processed');
}
使用Given/When/Then结构:
apex
@isTest
static void shouldUpdateStatus_WhenValidInput() {
    // Given
    List<Account> accounts = [SELECT Id FROM Account];

    // When
    Test.startTest();
    MyService.processAccounts(accounts);
    Test.stopTest();

    // Then
    List<Account> updated = [SELECT Id, Status__c FROM Account];
    Assert.areEqual(251, updated.size(), 'All accounts should be processed');
}

Negative Test — Exception Pattern

反向测试 —— 异常模式

Use try/catch with
Assert.fail
to verify expected exceptions:
apex
@isTest
static void shouldThrowException_WhenInvalidInput() {
    // Given
    List<Account> emptyList = new List<Account>();

    // When/Then
    Test.startTest();
    try {
        MyService.processAccounts(emptyList);
        Assert.fail('Expected MyCustomException to be thrown');
    } catch (MyCustomException e) {
        Assert.isTrue(e.getMessage().contains('cannot be empty'),
            'Exception message should indicate empty input');
    }
    Test.stopTest();
}
使用try/catch结合
Assert.fail
验证预期异常:
apex
@isTest
static void shouldThrowException_WhenInvalidInput() {
    // Given
    List<Account> emptyList = new List<Account>();

    // When/Then
    Test.startTest();
    try {
        MyService.processAccounts(emptyList);
        Assert.fail('Expected MyCustomException to be thrown');
    } catch (MyCustomException e) {
        Assert.isTrue(e.getMessage().contains('cannot be empty'),
            'Exception message should indicate empty input');
    }
    Test.stopTest();
}

Naming Convention

命名约定

  • should[ExpectedResult]_When[Scenario]
    :
    shouldSendNotification_WhenOpportunityClosedWon
  • [SubjectOrAction]_[Scenario]_[ExpectedResult]
    :
    AccountUpdate_ChangeName_Success
  • should[预期结果]_When[场景]
    shouldSendNotification_WhenOpportunityClosedWon
  • [主体或动作]_[场景]_[预期结果]
    AccountUpdate_ChangeName_Success

Step 3 — Run Tests

步骤3 —— 运行测试

Start narrow when debugging; widen after the fix is stable.
bash
undefined
调试时先从窄范围开始;修复稳定后再扩大范围。
bash
undefined

Single test class

单个测试类

sf apex run test --class-names MyServiceTest --result-format human --code-coverage --target-org <alias>
sf apex run test --class-names MyServiceTest --result-format human --code-coverage --target-org <alias>

Specific test methods

特定测试方法

sf apex run test --tests MyServiceTest.shouldUpdateStatus_WhenValidInput --result-format human --target-org <alias>
sf apex run test --tests MyServiceTest.shouldUpdateStatus_WhenValidInput --result-format human --target-org <alias>

All local tests

所有本地测试

sf apex run test --test-level RunLocalTests --result-format human --code-coverage --target-org <alias>
undefined
sf apex run test --test-level RunLocalTests --result-format human --code-coverage --target-org <alias>
undefined

Step 4 — Analyze Results

步骤4 —— 分析结果

Focus on:
  • failing methods — exception types and stack traces
  • uncovered lines and weak coverage areas
  • whether failures indicate bad test data, brittle assertions, or broken production logic
重点关注:
  • 失败的方法 —— 异常类型和堆栈跟踪
  • 未覆盖的代码行和薄弱的覆盖区域
  • 失败是否表明测试数据存在问题、断言不够健壮或生产逻辑已损坏

Step 5 — Fix Loop

步骤5 —— 修复循环

When tests fail, run a disciplined fix loop (max 3 iterations — stop and surface root cause if still failing):
  1. Read the failing test class and the class under test
  2. Identify root cause from error messages and stack traces
  3. Apply fix — adjust test data or assertions for test-side issues; delegate production code issues to the
    generating-apex
    skill
  4. Rerun the focused test before broader regression
  5. Repeat until all tests pass, iteration limit reached, or root cause requires design change
当测试失败时,执行规范的修复循环(最多3次迭代——如果仍失败,请停止并找出根本原因):
  1. 阅读失败的测试类和被测类
  2. 从错误信息和堆栈跟踪中确定根本原因
  3. 应用修复 —— 针对测试端问题调整测试数据或断言;针对生产代码问题请委托给
    generating-apex
    技能
  4. 在进行更广泛的回归测试之前,重新运行聚焦的测试
  5. 重复直到所有测试通过、达到迭代限制或根本原因需要设计变更

Step 6 — Validate Coverage

步骤6 —— 验证覆盖率

LevelCoveragePurpose
Production deploy75% minimumRequired by Salesforce
Recommended90%+Best practice target
Critical paths100%Business-critical code
Cover all paths: positive, negative/exception, bulk (251+ records), callout/async.
级别覆盖率用途
生产部署最低75%Salesforce要求
推荐值90%+最佳实践目标
关键路径100%业务关键代码
覆盖所有路径:正向、反向/异常、批量(251+条记录)、调用/异步。

What to Test by Component

按组件划分的测试内容

ComponentKey Test Scenarios
TriggerBulk insert/update/delete, recursion guard, field change detection
ServiceValid/invalid inputs, bulk operations, exception handling
ControllerPage load, action methods, view state
Batchstart/execute/finish, scope matching (batch size >= record count),
Database.Stateful
tracking, error handling, chaining (separate methods —
finish()
calling
Database.executeBatch()
throws
UnexpectedException
)
QueueableChaining (only first job runs in tests), bulkification, error handling, callout mocks before
Test.startTest()
CalloutSuccess response, error response, timeout
SelectorValid/null/empty inputs, bulk (251+), field population, sort order,
WITH USER_MODE
via
System.runAs
ScheduledDirect execution via
execute(null)
, CRON registration via
CronTrigger
query
Platform Event
Test.enableChangeDataCapture()
,
Test.getEventBus().deliver()
, verify subscriber side effects
组件关键测试场景
触发器批量插入/更新/删除、递归防护、字段变更检测
服务有效/无效输入、批量操作、异常处理
控制器页面加载、动作方法、视图状态
批处理start/execute/finish、范围匹配(批处理大小 >= 记录数)、
Database.Stateful
跟踪、错误处理、链式调用(需单独方法——
finish()
调用
Database.executeBatch()
会抛出
UnexpectedException
可队列项链式调用(测试中仅第一个作业运行)、批量处理能力、错误处理、
Test.startTest()
前的调用模拟
调用成功响应、错误响应、超时
选择器有效/null/空输入、批量(251+)、字段填充、排序顺序、通过
System.runAs
实现
WITH USER_MODE
定时作业通过
execute(null)
直接执行、通过
CronTrigger
查询注册CRON
平台事件
Test.enableChangeDataCapture()
Test.getEventBus().deliver()
、验证订阅者副作用

Output Expectations

输出预期

Deliverables per test class:
  • {ClassName}Test.cls
    +
    {ClassName}Test.cls-meta.xml
    (match API version of class under test; default
    66.0
    )
  • TestDataFactory.cls
    +
    TestDataFactory.cls-meta.xml
    (if not already present)
每个测试类的交付物:
  • {ClassName}Test.cls
    +
    {ClassName}Test.cls-meta.xml
    (与被测类的API版本匹配;默认
    66.0
  • TestDataFactory.cls
    +
    TestDataFactory.cls-meta.xml
    (如果尚未存在)

Reference Files

参考文件

Load on demand for detailed patterns:
ReferenceWhen to use
references/test-data-factory.mdTestDataFactory patterns, field overrides, duplicate rule handling
references/assertion-patterns.mdAssertion best practices, anti-patterns, common pitfalls
references/mocking-patterns.mdHttpCalloutMock, DML mocking, StubProvider, SOSL, Email, Platform Events
references/async-testing.mdBatch, Queueable, Future, Scheduled job testing
按需加载以获取详细模式:
参考文档使用场景
references/test-data-factory.mdTestDataFactory模式、字段覆盖、重复规则处理
references/assertion-patterns.md断言最佳实践、反模式、常见陷阱
references/mocking-patterns.mdHttpCalloutMock、DML模拟、StubProvider、SOSL、邮件、平台事件
references/async-testing.md批处理、可队列项、未来方法、定时作业测试