afv-library/skills/apex-test-class/references/assertion-patterns.md
Mohan Raj Rajamanickam 2320c50264
ci: publish skills as @salesforce/afv-skills npm package @W-21534193@ (#30)
* ci: update package details and add GitHub workflows for skills validation and release

* chore: update Node version, change license, and refactor skills validation script to TypeScript

* chore: remove unused deps

* fix: npm package

* fix: flatten skills to pass validation

* chore: add validation script to package.json and update GitHub workflow to use it

* chore: enhance skills validation and update workflows for npm publishing

* refactor: streamline skills validation process in workflow and script

* refactor: improve documentation and structure of skills validation script

* implement checks based on jeff's best practices doc

* chore: add pull request template for skill submissions

* chore: update pull request template with additional references and improve automated checks section

* chore: update pull request template to clarify naming convention with a warning for gerund form

* chore: update pull request template to reference skill authoring guide and enhance checklist structure

* chore: enhance GitHub workflows for skills validation and release process

* refactor: improve parsing logic for SKILL.md files and enhance error collection in validation

* chore: update validation checks to enforce character limits for skill names and descriptions

* fix: remove unnecessary whitespace in footer string in validate-skills.ts
2026-03-12 13:41:52 -07:00

6.4 KiB

Assertion Patterns

Assertion Methods

The System.Assert class provides methods to assert various conditions in test methods. All methods support an optional message parameter for better error reporting.

Method Use Case
System.Assert.areEqual(expected, actual, msg) Exact equality
System.Assert.areNotEqual(notExpected, actual, msg) Value should differ
System.Assert.isTrue(condition, msg) Boolean condition is true
System.Assert.isFalse(condition, msg) Boolean condition is false
System.Assert.isNull(value, msg) Value is null
System.Assert.isNotNull(value, msg) Value is not null
System.Assert.isInstanceOfType(instance, expectedType, msg) Instance is of specified type
System.Assert.isNotInstanceOfType(instance, notExpectedType, msg) Instance is not of specified type
System.Assert.fail(msg) Explicitly fail the test

Always include the message parameter - Makes test failures meaningful and easier to debug.

Note: Assertion failures are fatal errors that halt code execution. You cannot catch assertion failures using try/catch blocks, even though they're logged as exceptions.

Note: Call startTest() and stopTest() only once per test method. Wrap only the code under test between these calls, not setup or verification code.

Good vs Bad Assertions

Bad: No message, tests coverage not behavior

System.Assert.areEqual(true, result);
System.Assert.isTrue(accounts.size() > 0);

Good: Descriptive message, tests specific behavior

System.Assert.areEqual(true, result, 'Service should return true for valid input');
System.Assert.areEqual(200, accounts.size(), 'All 200 accounts should be processed');

Common Assertion Patterns

Collection Size

// Exact count
System.Assert.areEqual(200, results.size(), 'Should process all 200 records');

// Not empty
System.Assert.isFalse(results.isEmpty(), 'Results should not be empty');

// Empty
System.Assert.isTrue(results.isEmpty(), 'No results expected for invalid input');

Field Values

// Single record
System.Assert.areEqual('Processed', acc.Status__c, 'Account status should be updated to Processed');

// All records in collection
for (Account acc : updatedAccounts) {
    System.Assert.areEqual('Active', acc.Status__c, 
        'Account ' + acc.Name + ' should have Active status');
}

Exception Testing

@IsTest
private static void shouldThrowException_WhenInputInvalid() {
    Boolean exceptionThrown = false;
    String exceptionMessage = '';
    
    Test.startTest();
    try {
        MyService.process(null);
    } catch (MyCustomException e) {
        exceptionThrown = true;
        exceptionMessage = e.getMessage();
    }
    Test.stopTest();
    
    System.Assert.isTrue(exceptionThrown, 'MyCustomException should be thrown for null input');
    System.Assert.isTrue(exceptionMessage.contains('cannot be null'), 
        'Exception message should mention null input');
}

DML Results

// Insert success
Database.SaveResult[] results = Database.insert(accounts, false);
for (Database.SaveResult sr : results) {
    System.Assert.isTrue(sr.isSuccess(), 'Insert should succeed: ' + sr.getErrors());
}

// Expected failures
Database.SaveResult sr = Database.insert(invalidAccount, false);
System.Assert.isFalse(sr.isSuccess(), 'Insert should fail for invalid data');
System.Assert.isTrue(sr.getErrors()[0].getMessage().contains('REQUIRED_FIELD_MISSING'),
    'Error should indicate missing required field');

Comparing Objects

// Compare specific fields, not entire objects
System.Assert.areEqual(expected.Name, actual.Name, 'Names should match');
System.Assert.areEqual(expected.Status__c, actual.Status__c, 'Status should match');

// Or use JSON for deep comparison (use sparingly)
System.Assert.areEqual(
    JSON.serialize(expected), 
    JSON.serialize(actual), 
    'Objects should be identical'
);

Date/DateTime Assertions

// Exact date
System.Assert.areEqual(Date.today(), record.CreatedDate__c, 'Should be created today');

// Date within range
System.Assert.isTrue(record.DueDate__c >= Date.today(), 'Due date should be in the future');
System.Assert.isTrue(record.DueDate__c <= Date.today().addDays(30), 
    'Due date should be within 30 days');

Null Checks

// Should be null
System.Assert.isNull(result.ErrorMessage__c, 'No error expected for valid input');

// Should not be null
System.Assert.isNotNull(result.Id, 'Record should have been inserted');

Type Checking

// Verify instance is of expected type
Object result = MyService.processData();
System.Assert.isInstanceOfType(result, MyCustomClass.class, 
    'Result should be an instance of MyCustomClass');

// Verify instance is not of a specific type
Object handler = HandlerFactory.create('Account');
System.Assert.isNotInstanceOfType(handler, ContactHandler.class, 
    'Account handler should not be a ContactHandler');

Explicit Test Failures

// Use Assert.fail() when an exception should have been thrown but wasn't
@IsTest
private static void shouldThrowException_WhenInputInvalid() {
    try {
        MyService.process(null);
        System.Assert.fail('Expected MyCustomException to be thrown for null input');
    } catch (MyCustomException e) {
        // Exception was thrown as expected, test passes
        System.Assert.isTrue(e.getMessage().contains('cannot be null'), 
            'Exception message should mention null input');
    }
}

Anti-Patterns to Avoid

Testing implementation, not behavior

// Bad: Testing that a specific method was called
System.Assert.isTrue(MyClass.methodWasCalled, 'Method should be called');

// Good: Testing the observable outcome
System.Assert.areEqual('Expected Value', record.Field__c, 'Field should be updated');

Overly generic assertions

// Bad: Passes for any non-empty result
System.Assert.isTrue(results.size() > 0);

// Good: Verifies exact expected count
System.Assert.areEqual(200, results.size(), 'All 200 records should be returned');

Missing negative test assertions

// Bad: Only tests that no exception occurred
MyService.process(data); // Test passes if no exception

// Good: Verifies the actual outcome
Result r = MyService.process(data);
System.Assert.areEqual('Success', r.status, 'Processing should succeed');
System.Assert.areEqual(0, r.errorCount, 'No errors should occur');