afv-library/skills/generating-apex-test/references/test-patterns.md

78 lines
3.1 KiB
Markdown
Raw Normal View History

# Test Patterns by Component Type
Quick reference for choosing the right test pattern and asset template for each component type.
## Pattern Selection
| Component Under Test | Template | Key Scenarios |
|----------------------|----------|---------------|
| Service / Controller | [assets/basic-test.cls](../assets/basic-test.cls) | Valid input, null/invalid input, empty collection edge case |
| Trigger / Bulk DML | [assets/bulk-test.cls](../assets/bulk-test.cls) | 251-record insert/update/delete, governor limit verification |
| HTTP Callout | [assets/mock-callout-test.cls](../assets/mock-callout-test.cls) | Success response, error codes (400/401/500), timeout |
| DML-heavy service | [assets/dml-mock.cls](../assets/dml-mock.cls) | Fast unit tests via DML injection, no database |
| Interface mocking | [assets/stub-provider-example.cls](../assets/stub-provider-example.cls) | Dynamic behavior, method call tracking |
| Test data setup | [assets/test-data-factory.cls](../assets/test-data-factory.cls) | Consistent record creation across all tests |
## Naming Convention
Use the `should[ExpectedBehavior]_When[Condition]` pattern for all test methods:
```apex
@IsTest static void shouldCreateContact_WhenAccountIsActive() { }
@IsTest static void shouldThrowException_WhenEmailIsInvalid() { }
@IsTest static void shouldProcessAllRecords_WhenBulkInsert() { }
@IsTest static void shouldReturnError_WhenCalloutTimesOut() { }
```
## Test Structure (Given / When / Then)
Every test method follows this structure:
```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 Status__c FROM Account];
Assert.areEqual('Processed', updated[0].Status__c, 'Status should be updated');
}
```
## Component-Specific Guidance
### Triggers
- Always test at 251 records (crosses 200-record batch boundary)
- Test insert, update, and delete events separately
- Verify recursion guards and field-change detection
- Use `assertGovernorLimitsNotExceeded()` helper (see bulk-test.cls)
### Batch Apex
- Verify `start` query returns expected scope
- Test `execute` with full and partial batches
- Test `finish` for cleanup, chaining, or notifications
- See [async-testing.md](async-testing.md) for `Test.stopTest()` patterns
### Queueable / Future
- `Test.stopTest()` forces synchronous execution
- Only the first chained queueable runs in tests
- Mock callouts before `Test.startTest()` if the job makes HTTP requests
- See [async-testing.md](async-testing.md) for chaining and callout patterns
### Callouts
- Salesforce requires `HttpCalloutMock` -- real HTTP is blocked in tests
- Test success, error codes, and timeout scenarios
- For complex response bodies, use `StaticResourceCalloutMock`
- See [mocking-patterns.md](mocking-patterns.md) for multi-endpoint and validation mocks
### Scheduled Apex
- Verify CRON registration with `CronTrigger` query
- Test execution by calling `execute(null)` directly
- See [async-testing.md](async-testing.md) for schedule testing patterns