generating-apex-test
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGenerating Apex Tests
生成Apex测试
Generate production-ready Apex test classes and run disciplined test-fix loops with coverage analysis.
生成可用于生产环境的Apex测试类,并结合覆盖率分析执行规范的测试修复循环。
Core Principles
核心原则
- 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 and
_NullInput_as separate test methods_EmptyInput_ - Bulkify tests — test with 251+ records to cross the 200-record trigger batch boundary. Batch Apex exception: in test context only one invocation runs, so set
execute(). See references/async-testing.mdbatchSize >= testRecordCount - Isolate test data — every must delegate record creation to a
@TestSetupclass. If none exists, create one first. Never build record lists inline inTestDataFactory. Never rely on org data (@TestSetup) or hardcoded IDs. For duplicate rule handling, see references/test-data-factory.mdSeeAllData=false - 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
- Use class only —
Assert,Assert.areEqual,Assert.isTrue, etc. Never use legacyAssert.fail,System.assert, orSystem.assertEqualsSystem.assertNotEquals - Mock external boundaries — use for callouts,
HttpCalloutMockfor SOSL, DML mock classes for database isolation. Design for testability via constructor injection. See references/mocking-patterns.mdTest.setFixedSearchResults - Test negative paths — validate error handling and exception scenarios, not just happy paths
- Wrap with start/stop — pair with
Test.startTest()to reset governor limits and force async executionTest.stopTest()
- 一个方法对应一种行为 —— 每个测试方法仅验证一种场景。将正向、反向和批量测试分开。绝不要在一个方法中组合相关但不同的输入(例如null和空值)—— 应创建和
_NullInput_作为独立的测试方法_EmptyInput_ - 测试批量处理能力 —— 使用251+条记录进行测试,以跨越200条记录的触发器批处理边界。批处理Apex例外情况:在测试环境中仅会运行一次调用,因此需设置
execute()。详情请参阅references/async-testing.mdbatchSize >= testRecordCount - 隔离测试数据 —— 每个都必须将记录创建委托给
@TestSetup类。如果该类不存在,请先创建。绝不要在TestDataFactory中内联构建记录列表。绝不要依赖组织数据(@TestSetup)或硬编码ID。关于重复规则的处理,请参阅references/test-data-factory.mdSeeAllData=false - 有意义地断言 —— 使用从测试数据设置中计算出的精确预期值。当值是确定的时,绝不要使用范围断言或近似计数。始终包含失败提示信息。详情请参阅references/assertion-patterns.md
- 仅使用类 —— 使用
Assert、Assert.areEqual、Assert.isTrue等方法。绝不要使用旧版的Assert.fail、System.assert或System.assertEqualsSystem.assertNotEquals - 模拟外部边界 —— 对调用使用,对SOSL使用
HttpCalloutMock,对数据库隔离使用DML模拟类。通过构造函数注入实现可测试性设计。详情请参阅references/mocking-patterns.mdTest.setFixedSearchResults - 测试反向路径 —— 验证错误处理和异常场景,而不仅仅是正常路径
- 用start/stop包裹 —— 将与
Test.startTest()配对使用,以重置 governor 限制并强制执行异步操作Test.stopTest()
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-Pattern | Fix |
|---|---|
| SOQL/DML inside loops | Query once before the loop; use |
| Magic numbers in assertions | Derive 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 | Catch the specific expected type (e.g., |
| 反模式 | 修复方案 |
|---|---|
| 循环内的SOQL/DML | 在循环前查询一次;使用 |
| 断言中的魔术数字 | 从设置常量中推导预期值 |
| 上帝测试类(超过500行) | 按行为领域拆分为多个测试类 |
| 长测试方法(超过30行) | 将Given/When/Then提取到辅助方法中 |
捕获通用 | 捕获特定的预期类型(例如 |
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:
- — the test class (use assets/test-class-template.cls as starting point)
{ClassName}Test.cls - — the metadata file:
{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>If no exists in the project, create + using assets/test-data-factory-template.cls.
TestDataFactoryTestDataFactory.clsTestDataFactory.cls-meta.xml应用资产模板和参考文档中的结构、命名约定和模式。
必填 —— 文件交付物: 每个测试类都必须创建以下两个文件:
- —— 测试类(以assets/test-class-template.cls为起点)
{ClassName}Test.cls - —— 元数据文件:
{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>如果项目中不存在,请使用assets/test-data-factory-template.cls创建 + 。
TestDataFactoryTestDataFactory.clsTestDataFactory.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 to verify expected exceptions:
Assert.failapex
@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.failapex
@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
undefinedSingle 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>
undefinedsf apex run test --test-level RunLocalTests --result-format human --code-coverage --target-org <alias>
undefinedStep 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):
- Read the failing test class and the class under test
- Identify root cause from error messages and stack traces
- Apply fix — adjust test data or assertions for test-side issues; delegate production code issues to the skill
generating-apex - Rerun the focused test before broader regression
- Repeat until all tests pass, iteration limit reached, or root cause requires design change
当测试失败时,执行规范的修复循环(最多3次迭代——如果仍失败,请停止并找出根本原因):
- 阅读失败的测试类和被测类
- 从错误信息和堆栈跟踪中确定根本原因
- 应用修复 —— 针对测试端问题调整测试数据或断言;针对生产代码问题请委托给技能
generating-apex - 在进行更广泛的回归测试之前,重新运行聚焦的测试
- 重复直到所有测试通过、达到迭代限制或根本原因需要设计变更
Step 6 — Validate Coverage
步骤6 —— 验证覆盖率
| Level | Coverage | Purpose |
|---|---|---|
| Production deploy | 75% minimum | Required by Salesforce |
| Recommended | 90%+ | Best practice target |
| Critical paths | 100% | Business-critical code |
Cover all paths: positive, negative/exception, bulk (251+ records), callout/async.
| 级别 | 覆盖率 | 用途 |
|---|---|---|
| 生产部署 | 最低75% | Salesforce要求 |
| 推荐值 | 90%+ | 最佳实践目标 |
| 关键路径 | 100% | 业务关键代码 |
覆盖所有路径:正向、反向/异常、批量(251+条记录)、调用/异步。
What to Test by Component
按组件划分的测试内容
| Component | Key Test Scenarios |
|---|---|
| Trigger | Bulk insert/update/delete, recursion guard, field change detection |
| Service | Valid/invalid inputs, bulk operations, exception handling |
| Controller | Page load, action methods, view state |
| Batch | start/execute/finish, scope matching (batch size >= record count), |
| Queueable | Chaining (only first job runs in tests), bulkification, error handling, callout mocks before |
| Callout | Success response, error response, timeout |
| Selector | Valid/null/empty inputs, bulk (251+), field population, sort order, |
| Scheduled | Direct execution via |
| Platform Event | |
| 组件 | 关键测试场景 |
|---|---|
| 触发器 | 批量插入/更新/删除、递归防护、字段变更检测 |
| 服务 | 有效/无效输入、批量操作、异常处理 |
| 控制器 | 页面加载、动作方法、视图状态 |
| 批处理 | start/execute/finish、范围匹配(批处理大小 >= 记录数)、 |
| 可队列项 | 链式调用(测试中仅第一个作业运行)、批量处理能力、错误处理、 |
| 调用 | 成功响应、错误响应、超时 |
| 选择器 | 有效/null/空输入、批量(251+)、字段填充、排序顺序、通过 |
| 定时作业 | 通过 |
| 平台事件 | |
Output Expectations
输出预期
Deliverables per test class:
- +
{ClassName}Test.cls(match API version of class under test; default{ClassName}Test.cls-meta.xml)66.0 - +
TestDataFactory.cls(if not already present)TestDataFactory.cls-meta.xml
每个测试类的交付物:
- +
{ClassName}Test.cls(与被测类的API版本匹配;默认{ClassName}Test.cls-meta.xml)66.0 - +
TestDataFactory.cls(如果尚未存在)TestDataFactory.cls-meta.xml
Reference Files
参考文件
Load on demand for detailed patterns:
| Reference | When to use |
|---|---|
| references/test-data-factory.md | TestDataFactory patterns, field overrides, duplicate rule handling |
| references/assertion-patterns.md | Assertion best practices, anti-patterns, common pitfalls |
| references/mocking-patterns.md | HttpCalloutMock, DML mocking, StubProvider, SOSL, Email, Platform Events |
| references/async-testing.md | Batch, Queueable, Future, Scheduled job testing |
按需加载以获取详细模式:
| 参考文档 | 使用场景 |
|---|---|
| references/test-data-factory.md | TestDataFactory模式、字段覆盖、重复规则处理 |
| references/assertion-patterns.md | 断言最佳实践、反模式、常见陷阱 |
| references/mocking-patterns.md | HttpCalloutMock、DML模拟、StubProvider、SOSL、邮件、平台事件 |
| references/async-testing.md | 批处理、可队列项、未来方法、定时作业测试 |