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

3.1 KiB

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 Valid input, null/invalid input, empty collection edge case
Trigger / Bulk DML assets/bulk-test.cls 251-record insert/update/delete, governor limit verification
HTTP Callout assets/mock-callout-test.cls Success response, error codes (400/401/500), timeout
DML-heavy service assets/dml-mock.cls Fast unit tests via DML injection, no database
Interface mocking assets/stub-provider-example.cls Dynamic behavior, method call tracking
Test data setup assets/test-data-factory.cls Consistent record creation across all tests

Naming Convention

Use the should[ExpectedBehavior]_When[Condition] pattern for all test methods:

@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:

@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 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 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 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 for schedule testing patterns