platform-apex-test-generate
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, runn
By forcedotcom · 6,087 installs
npx skills add forcedotcom/sf-skills --skill platform-apex-test-generate
Source repository · Upstream listing
Generating Apex Tests
Generate production ready Apex test classes and run disciplined test fix loops with coverage analysis.
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](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](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](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](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
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:
1. {ClassName}Test.cls — the test class (use [assets/test class template.cls](assets/test class template.cls) as starting point)
2. {ClassName}Test.cls meta.xml — the metadata file:
If no TestDataFactory exists in the project, create TestDataFactory.cls + TestDataFactory.cls meta.xml using [assets/test data factory template.cls](assets/test data factory template.cls).
@TestSetup Example
Test Method Structure
Use Given/When/Then:
Negative Test — Exception Pattern
Use try/catch with Assert.fail to verify expected exceptions:
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.
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
when class metadata crosses from versions 66.0 and below to 67.0 and above, check explicit sharing, decide user/system mode per operation, grant required CRUD/FLS in test users or permission sets, and rerun affected tests
Step 5 — Fix Loop
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 platform apex generate skill
4. Rerun the focused test before broader regression
5. 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; default 66.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](references/test data factory.md) TestDataFactory patterns, field overrides, duplicate rule handling
[references/assertion patterns.md](references/assertion patterns.md) Assertion best practices, anti patterns, common pitfalls
[references/mocking patterns.md](references/mocking patterns.md) HttpCalloutMock, DML mocking, StubProvider, SOSL, Email, Platform Events
[references/async testing.md](references/async testing.md) Batch, Queueable, Future, Scheduled job testing