generating-apex-test
forcedotcom/sf-skills
Generate and validate Apex test classes with TestDataFactory patterns, bulk testing, mocking, and assertion best practices.
What is generating-apex-test?
This skill generates production-ready Apex test classes following Salesforce best practices, including TestDataFactory patterns, bulk testing (251+ records), mocking strategies, and disciplined test-fix loops. Use it when creating new Apex test classes, improving coverage, debugging failing tests, or implementing testing patterns for triggers, services, controllers, batch jobs, and integrations.
- Generate test classes with one behavior per method and Given/When/Then structure
- Create and manage TestDataFactory classes for isolated, reusable test data
- Implement bulk testing with 251+ records to cross trigger batch boundaries
- Apply mocking strategies for external callouts, SOSL, and database isolation
- Run disciplined test-fix loops with coverage analysis and focused debugging
- Validate assertions using Assert class with meaningful failure messages
How to install generating-apex-test
npx skills add https://github.com/forcedotcom/sf-skills --skill generating-apex-test- Salesforce CLI (sf) installed and configured
- Target org alias configured for test execution
- Existing production Apex code to test (use generating-apex skill for production code)
How to use generating-apex-test
- 1.Gather context: identify target production class(es), existing test factories, desired scope, and coverage threshold
- 2.Generate test class using test-class-template.cls and create corresponding .cls-meta.xml file
- 3.Create TestDataFactory.cls if none exists, using test-data-factory-template.cls
- 4.Write test methods following Given/When/Then structure with Test.startTest()/Test.stopTest() wrapping
- 5.Run focused tests: sf apex run test --class-names or --tests with --code-coverage flag
- 6.Analyze results for failing methods, uncovered lines, and weak coverage areas
- 7.Execute disciplined fix loop (max 3 iterations): read failure, identify root cause, apply fix, rerun focused test
- 8.Validate final coverage meets 75% minimum (90%+ recommended) across all paths
Use cases
- Creating new Apex test classes for triggers, services, controllers, and batch jobs
- Improving test coverage from 75% minimum to 90%+ recommended levels
- Debugging and fixing failing Apex tests with root cause analysis
- Running test execution and coverage analysis against org aliases
- Implementing testing patterns for queueables, scheduled jobs, and integrations
- Salesforce developers writing Apex test classes
- QA engineers validating Apex code coverage and quality
- Development teams enforcing testing standards and best practices
- Developers debugging failing tests in test-fix loops
generating-apex-test FAQ
Use generating-apex-test for Apex test classes (*Test.cls, *_Test.cls files), test data factories, and test-fix loops. Use generating-apex for production Apex code only. Do NOT use this skill for Jest/LWC tests.
TestDataFactory is a dedicated class that centralizes test data creation, ensuring isolation and reusability. Every @TestSetup must delegate record creation to TestDataFactory—never build records inline or rely on org data. If none exists, create one first using the test-data-factory-template.cls.
Triggers batch at 200 records. Testing with 251+ records ensures your trigger logic works correctly across the batch boundary. For Batch Apex in test context, set batchSize >= testRecordCount since only one execute() invocation runs.
Use the Assert class only (Assert.areEqual, Assert.isTrue, Assert.fail, etc.). Never use legacy System.assert, System.assertEquals, or System.assertNotEquals. Always include meaningful failure messages.
Run a max 3-iteration fix loop: (1) read the failing test and production code, (2) identify root cause from error messages, (3) apply fix (test-side or production-side), (4) rerun focused test. If still failing after 3 iterations, surface the root cause and stop.
Full instructions (SKILL.md)
Source of truth, from forcedotcom/sf-skills.
name: generating-apex-test description: "Generate and validate Apex test classes with TestDataFactory patterns, bulk testing (251+ records), mocking strategies, assertion best practices, and disciplined test-fix loops. Use this skill when creating new Apex test classes, improving test coverage, debugging and fixing failing Apex tests, running test execution and coverage analysis, or implementing testing patterns for triggers, services, controllers, batch jobs, queueables, and integrations. Triggers on *Test.cls, *_Test.cls files, sf apex run test workflows, coverage reports, test-fix loops. Do NOT trigger for production Apex code (use generating-apex) or Jest/LWC tests." metadata: version: "1.0"
Generating Apex Tests
Generate production-ready Apex test classes and run disciplined test-fix loops with coverage analysis.
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
_NullInput_and_EmptyInput_as separate test methods - 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 setbatchSize >= testRecordCount. See references/async-testing.md - Isolate test data — every
@TestSetupmust delegate record creation to aTestDataFactoryclass. 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 - 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
Assertclass only —Assert.areEqual,Assert.isTrue,Assert.fail, etc. Never use legacySystem.assert,System.assertEquals, orSystem.assertNotEquals - Mock external boundaries — use
HttpCalloutMockfor callouts,Test.setFixedSearchResultsfor SOSL, DML mock classes for database isolation. Design for testability via constructor injection. See references/mocking-patterns.md - Test negative paths — validate error handling and exception scenarios, not just happy paths
- Wrap with start/stop — pair
Test.startTest()withTest.stopTest()to reset governor limits and force async execution
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 Code Anti-Patterns
| Anti-Pattern | Fix |
|---|---|
| SOQL/DML inside loops | Query once before the loop; use Map<Id, SObject> for lookups |
| 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 Exception catch | Catch the specific expected type (e.g., DmlException) |
Workflow
Step 1 — Gather Context
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
Step 2 — Generate the Test Class
Apply the structure, naming conventions, and patterns from the asset templates and reference docs.
MANDATORY — File Deliverables: For every test class, create BOTH files:
{ClassName}Test.cls— the test class (use assets/test-class-template.cls as starting point){ClassName}Test.cls-meta.xml— the metadata file:
<?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.
@TestSetup Example
@TestSetup
static void setupTestData() {
List<Account> accounts = TestDataFactory.createAccounts(251, true);
}
Test Method Structure
Use Given/When/Then:
@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:
@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
Step 3 — Run Tests
Start narrow when debugging; widen after the fix is stable.
# Single test class
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>
# All local tests
sf apex run test --test-level RunLocalTests --result-format human --code-coverage --target-org <alias>
Step 4 — Analyze Results
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
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
generating-apexskill - Rerun the focused test before broader regression
- Repeat until all tests pass, iteration limit reached, or root cause requires design change
Step 6 — Validate Coverage
| 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.
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), Database.Stateful tracking, error handling, chaining (separate methods — finish() calling Database.executeBatch() throws UnexpectedException) |
| Queueable | Chaining (only first job runs in tests), bulkification, error handling, callout mocks before Test.startTest() |
| Callout | Success response, error response, timeout |
| Selector | Valid/null/empty inputs, bulk (251+), field population, sort order, WITH USER_MODE via System.runAs |
| Scheduled | Direct execution via execute(null), CRON registration via CronTrigger query |
| Platform Event | Test.enableChangeDataCapture(), Test.getEventBus().deliver(), verify subscriber side effects |
Output Expectations
Deliverables per test class:
{ClassName}Test.cls+{ClassName}Test.cls-meta.xml(match API version of class under test; default66.0)TestDataFactory.cls+TestDataFactory.cls-meta.xml(if not already present)
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 |
Related skills
More from forcedotcom/sf-skills and the wider catalog.

generating-custom-application
Create and configure tab-based Salesforce Lightning Custom Applications with navigation, branding, and action overrides.

generating-custom-field
Generate and validate Salesforce Custom Field metadata with constraints to prevent deployment errors.

generating-custom-lightning-type
Create Custom Lightning Types (CLTs) for Einstein Agent actions and structured schemas

generating-custom-object
Create and validate Salesforce Custom Object metadata XML with correct sharing models and field configurations.

generating-custom-tab
Create and configure Salesforce Custom Tabs for objects, web content, and Visualforce pages.

generating-flexipage
Create and customize Salesforce Lightning pages (FlexiPages) with CLI-bootstrapped XML generation.