mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
Merge pull request #6 from mitchspano/apex_updates
Test method annotations to `@IsTest` and `System.Assert` class
This commit is contained in:
commit
85c1fe6075
@ -54,7 +54,7 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
|
||||
// TODO: Add assertions
|
||||
// List<Opportunity> inserted = [SELECT Id, Name FROM Opportunity WHERE Name = 'Valid Opp'];
|
||||
// System.assertEquals(1, inserted.size(), 'Should insert 1 record');
|
||||
// System.Assert.areEqual(1, inserted.size(), 'Should insert 1 record');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,13 +82,13 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
} catch (DmlException e) {
|
||||
exceptionThrown = true;
|
||||
// TODO: Assert error message
|
||||
// System.assert(e.getMessage().contains('must have Amount'),
|
||||
// System.Assert.isTrue(e.getMessage().contains('must have Amount'),
|
||||
// 'Should throw validation error');
|
||||
}
|
||||
|
||||
Test.stopTest();
|
||||
|
||||
// System.assert(exceptionThrown, 'Should have thrown an exception');
|
||||
// System.Assert.isTrue(exceptionThrown, 'Should have thrown an exception');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,7 +109,7 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
|
||||
// TODO: Add assertions
|
||||
// Opportunity updated = [SELECT Description FROM Opportunity WHERE Id = :testOpps[0].Id];
|
||||
// System.assert(updated.Description.contains('Stage changed'),
|
||||
// System.Assert.isTrue(updated.Description.contains('Stage changed'),
|
||||
// 'Description should be updated');
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
|
||||
// TODO: Query for related records created by handler
|
||||
// List<Task> createdTasks = [SELECT Id FROM Task];
|
||||
// System.assertEquals(1, createdTasks.size(), 'Should create 1 task');
|
||||
// System.Assert.areEqual(1, createdTasks.size(), 'Should create 1 task');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,8 +162,8 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
|
||||
// TODO: Query for side effects (e.g., Tasks created)
|
||||
// List<Task> tasks = [SELECT Id, Subject FROM Task WHERE WhatId = :testOpps[0].Id];
|
||||
// System.assertEquals(1, tasks.size(), 'Should create 1 task');
|
||||
// System.assertEquals('Send thank-you', tasks[0].Subject);
|
||||
// System.Assert.areEqual(1, tasks.size(), 'Should create 1 task');
|
||||
// System.Assert.areEqual('Send thank-you', tasks[0].Subject);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,7 +191,7 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
|
||||
// TODO: Assert all records inserted successfully
|
||||
// List<Opportunity> inserted = [SELECT Id FROM Opportunity WHERE Name LIKE 'Bulk Opp%'];
|
||||
// System.assertEquals(200, inserted.size(), 'Should insert all 200 records');
|
||||
// System.Assert.areEqual(200, inserted.size(), 'Should insert all 200 records');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,7 +231,7 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
|
||||
// TODO: Assert only qualifying records triggered side effects
|
||||
// List<Task> tasks = [SELECT Id FROM Task WHERE WhatId IN :testOpps];
|
||||
// System.assertEquals(25, tasks.size(), 'Should create tasks for 25 qualifying records');
|
||||
// System.Assert.areEqual(25, tasks.size(), 'Should create tasks for 25 qualifying records');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -257,9 +257,9 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
Test.stopTest();
|
||||
|
||||
// Assert we're under governor limits
|
||||
System.assert(Limits.getDmlStatements() < Limits.getLimitDmlStatements(),
|
||||
System.Assert.isTrue(Limits.getDmlStatements() < Limits.getLimitDmlStatements(),
|
||||
'Should not exceed DML statement limit');
|
||||
System.assert(Limits.getQueries() < Limits.getLimitQueries(),
|
||||
System.Assert.isTrue(Limits.getQueries() < Limits.getLimitQueries(),
|
||||
'Should not exceed SOQL query limit');
|
||||
}
|
||||
|
||||
@ -278,7 +278,7 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
Test.stopTest();
|
||||
|
||||
// If we get here without exception, test passes
|
||||
System.assert(true, 'Handler should handle empty collections gracefully');
|
||||
System.Assert.isTrue(true, 'Handler should handle empty collections gracefully');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -310,11 +310,11 @@ private class [ObjectName]TriggerHandlerTest {
|
||||
WHERE WhatId IN :oppIds
|
||||
];
|
||||
|
||||
System.assertEquals(expectedCount, tasks.size(),
|
||||
System.Assert.areEqual(expectedCount, tasks.size(),
|
||||
'Should create ' + expectedCount + ' task(s)');
|
||||
|
||||
if (expectedCount > 0) {
|
||||
System.assertEquals(subject, tasks[0].Subject,
|
||||
System.Assert.areEqual(subject, tasks[0].Subject,
|
||||
'Task subject should match');
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ description: Apex test class generation with TestDataFactory patterns, bulk test
|
||||
## Test Class Structure
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
@IsTest
|
||||
private class MyServiceTest {
|
||||
|
||||
@TestSetup
|
||||
@ -25,7 +25,7 @@ private class MyServiceTest {
|
||||
List<Account> accounts = TestDataFactory.createAccounts(200, true);
|
||||
}
|
||||
|
||||
@isTest
|
||||
@IsTest
|
||||
static void shouldPerformExpectedBehavior_WhenValidInput() {
|
||||
// Given: Setup specific test state
|
||||
List<Account> accounts = [SELECT Id, Name FROM Account];
|
||||
@ -37,13 +37,13 @@ private class MyServiceTest {
|
||||
|
||||
// Then: Assert expected outcomes
|
||||
List<Account> updated = [SELECT Id, Status__c FROM Account];
|
||||
System.assertEquals(200, updated.size(), 'All accounts should be processed');
|
||||
System.Assert.areEqual(200, updated.size(), 'All accounts should be processed');
|
||||
for (Account acc : updated) {
|
||||
System.assertEquals('Processed', acc.Status__c, 'Status should be updated');
|
||||
System.Assert.areEqual('Processed', acc.Status__c, 'Status should be updated');
|
||||
}
|
||||
}
|
||||
|
||||
@isTest
|
||||
@IsTest
|
||||
static void shouldThrowException_WhenInvalidInput() {
|
||||
// Given
|
||||
List<Account> emptyList = new List<Account>();
|
||||
@ -52,9 +52,9 @@ private class MyServiceTest {
|
||||
Test.startTest();
|
||||
try {
|
||||
MyService.processAccounts(emptyList);
|
||||
System.assert(false, 'Expected MyCustomException to be thrown');
|
||||
System.Assert.fail('Expected MyCustomException to be thrown');
|
||||
} catch (MyCustomException e) {
|
||||
System.assert(e.getMessage().contains('cannot be empty'),
|
||||
System.Assert.isTrue(e.getMessage().contains('cannot be empty'),
|
||||
'Exception message should indicate empty input');
|
||||
}
|
||||
Test.stopTest();
|
||||
|
||||
@ -2,28 +2,41 @@
|
||||
|
||||
## 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.assertEquals(expected, actual, msg)` | Exact equality |
|
||||
| `System.assertNotEquals(expected, actual, msg)` | Value should differ |
|
||||
| `System.assert(condition, msg)` | Boolean condition |
|
||||
| `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 third parameter (message)** - Makes test failures meaningful.
|
||||
**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
|
||||
|
||||
```apex
|
||||
System.assertEquals(true, result);
|
||||
System.assert(accounts.size() > 0);
|
||||
System.Assert.areEqual(true, result);
|
||||
System.Assert.isTrue(accounts.size() > 0);
|
||||
```
|
||||
|
||||
### ✅ Good: Descriptive message, tests specific behavior
|
||||
|
||||
```apex
|
||||
System.assertEquals(true, result, 'Service should return true for valid input');
|
||||
System.assertEquals(200, accounts.size(), 'All 200 accounts should be processed');
|
||||
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
|
||||
@ -32,24 +45,24 @@ System.assertEquals(200, accounts.size(), 'All 200 accounts should be processed'
|
||||
|
||||
```apex
|
||||
// Exact count
|
||||
System.assertEquals(200, results.size(), 'Should process all 200 records');
|
||||
System.Assert.areEqual(200, results.size(), 'Should process all 200 records');
|
||||
|
||||
// Not empty
|
||||
System.assert(!results.isEmpty(), 'Results should not be empty');
|
||||
System.Assert.isFalse(results.isEmpty(), 'Results should not be empty');
|
||||
|
||||
// Empty
|
||||
System.assert(results.isEmpty(), 'No results expected for invalid input');
|
||||
System.Assert.isTrue(results.isEmpty(), 'No results expected for invalid input');
|
||||
```
|
||||
|
||||
### Field Values
|
||||
|
||||
```apex
|
||||
// Single record
|
||||
System.assertEquals('Processed', acc.Status__c, 'Account status should be updated to Processed');
|
||||
System.Assert.areEqual('Processed', acc.Status__c, 'Account status should be updated to Processed');
|
||||
|
||||
// All records in collection
|
||||
for (Account acc : updatedAccounts) {
|
||||
System.assertEquals('Active', acc.Status__c,
|
||||
System.Assert.areEqual('Active', acc.Status__c,
|
||||
'Account ' + acc.Name + ' should have Active status');
|
||||
}
|
||||
```
|
||||
@ -57,8 +70,8 @@ for (Account acc : updatedAccounts) {
|
||||
### Exception Testing
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldThrowException_WhenInputInvalid() {
|
||||
@IsTest
|
||||
private static void shouldThrowException_WhenInputInvalid() {
|
||||
Boolean exceptionThrown = false;
|
||||
String exceptionMessage = '';
|
||||
|
||||
@ -71,8 +84,8 @@ static void shouldThrowException_WhenInputInvalid() {
|
||||
}
|
||||
Test.stopTest();
|
||||
|
||||
System.assert(exceptionThrown, 'MyCustomException should be thrown for null input');
|
||||
System.assert(exceptionMessage.contains('cannot be null'),
|
||||
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');
|
||||
}
|
||||
```
|
||||
@ -83,13 +96,13 @@ static void shouldThrowException_WhenInputInvalid() {
|
||||
// Insert success
|
||||
Database.SaveResult[] results = Database.insert(accounts, false);
|
||||
for (Database.SaveResult sr : results) {
|
||||
System.assert(sr.isSuccess(), 'Insert should succeed: ' + sr.getErrors());
|
||||
System.Assert.isTrue(sr.isSuccess(), 'Insert should succeed: ' + sr.getErrors());
|
||||
}
|
||||
|
||||
// Expected failures
|
||||
Database.SaveResult sr = Database.insert(invalidAccount, false);
|
||||
System.assert(!sr.isSuccess(), 'Insert should fail for invalid data');
|
||||
System.assert(sr.getErrors()[0].getMessage().contains('REQUIRED_FIELD_MISSING'),
|
||||
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');
|
||||
```
|
||||
|
||||
@ -97,11 +110,11 @@ System.assert(sr.getErrors()[0].getMessage().contains('REQUIRED_FIELD_MISSING'),
|
||||
|
||||
```apex
|
||||
// Compare specific fields, not entire objects
|
||||
System.assertEquals(expected.Name, actual.Name, 'Names should match');
|
||||
System.assertEquals(expected.Status__c, actual.Status__c, 'Status should match');
|
||||
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.assertEquals(
|
||||
System.Assert.areEqual(
|
||||
JSON.serialize(expected),
|
||||
JSON.serialize(actual),
|
||||
'Objects should be identical'
|
||||
@ -112,11 +125,11 @@ System.assertEquals(
|
||||
|
||||
```apex
|
||||
// Exact date
|
||||
System.assertEquals(Date.today(), record.CreatedDate__c, 'Should be created today');
|
||||
System.Assert.areEqual(Date.today(), record.CreatedDate__c, 'Should be created today');
|
||||
|
||||
// Date within range
|
||||
System.assert(record.DueDate__c >= Date.today(), 'Due date should be in the future');
|
||||
System.assert(record.DueDate__c <= Date.today().addDays(30),
|
||||
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');
|
||||
```
|
||||
|
||||
@ -124,10 +137,41 @@ System.assert(record.DueDate__c <= Date.today().addDays(30),
|
||||
|
||||
```apex
|
||||
// Should be null
|
||||
System.assertEquals(null, result.ErrorMessage__c, 'No error expected for valid input');
|
||||
System.Assert.isNull(result.ErrorMessage__c, 'No error expected for valid input');
|
||||
|
||||
// Should not be null
|
||||
System.assertNotEquals(null, result.Id, 'Record should have been inserted');
|
||||
System.Assert.isNotNull(result.Id, 'Record should have been inserted');
|
||||
```
|
||||
|
||||
### Type Checking
|
||||
|
||||
```apex
|
||||
// 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
|
||||
|
||||
```apex
|
||||
// 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
|
||||
@ -136,20 +180,20 @@ System.assertNotEquals(null, result.Id, 'Record should have been inserted');
|
||||
|
||||
```apex
|
||||
// Bad: Testing that a specific method was called
|
||||
System.assert(MyClass.methodWasCalled, 'Method should be called');
|
||||
System.Assert.isTrue(MyClass.methodWasCalled, 'Method should be called');
|
||||
|
||||
// Good: Testing the observable outcome
|
||||
System.assertEquals('Expected Value', record.Field__c, 'Field should be updated');
|
||||
System.Assert.areEqual('Expected Value', record.Field__c, 'Field should be updated');
|
||||
```
|
||||
|
||||
### ❌ Overly generic assertions
|
||||
|
||||
```apex
|
||||
// Bad: Passes for any non-empty result
|
||||
System.assert(results.size() > 0);
|
||||
System.Assert.isTrue(results.size() > 0);
|
||||
|
||||
// Good: Verifies exact expected count
|
||||
System.assertEquals(200, results.size(), 'All 200 records should be returned');
|
||||
System.Assert.areEqual(200, results.size(), 'All 200 records should be returned');
|
||||
```
|
||||
|
||||
### ❌ Missing negative test assertions
|
||||
@ -160,6 +204,6 @@ MyService.process(data); // Test passes if no exception
|
||||
|
||||
// Good: Verifies the actual outcome
|
||||
Result r = MyService.process(data);
|
||||
System.assertEquals('Success', r.status, 'Processing should succeed');
|
||||
System.assertEquals(0, r.errorCount, 'No errors should occur');
|
||||
System.Assert.areEqual('Success', r.status, 'Processing should succeed');
|
||||
System.Assert.areEqual(0, r.errorCount, 'No errors should occur');
|
||||
```
|
||||
@ -9,8 +9,8 @@
|
||||
### Basic Batch Test
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldProcessAllRecords_WhenBatchExecutes() {
|
||||
@IsTest
|
||||
private static void shouldProcessAllRecords_WhenBatchExecutes() {
|
||||
// Given: Create test data
|
||||
List<Account> accounts = TestDataFactory.createAccounts(200, true);
|
||||
|
||||
@ -23,7 +23,7 @@ static void shouldProcessAllRecords_WhenBatchExecutes() {
|
||||
// Then: Verify results
|
||||
List<Account> updated = [SELECT Id, Status__c FROM Account];
|
||||
for (Account acc : updated) {
|
||||
System.assertEquals('Processed', acc.Status__c,
|
||||
System.Assert.areEqual('Processed', acc.Status__c,
|
||||
'Batch should update all account statuses');
|
||||
}
|
||||
}
|
||||
@ -32,8 +32,8 @@ static void shouldProcessAllRecords_WhenBatchExecutes() {
|
||||
### Testing Batch with Failures
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldLogErrors_WhenRecordsFail() {
|
||||
@IsTest
|
||||
private static void shouldLogErrors_WhenRecordsFail() {
|
||||
// Given: Create mix of valid and invalid records
|
||||
List<Account> accounts = TestDataFactory.createAccounts(198, true);
|
||||
|
||||
@ -55,15 +55,15 @@ static void shouldLogErrors_WhenRecordsFail() {
|
||||
|
||||
// Then
|
||||
List<Error_Log__c> errors = [SELECT Id, Message__c FROM Error_Log__c];
|
||||
System.assertEquals(2, errors.size(), 'Should log 2 failed records');
|
||||
System.Assert.areEqual(2, errors.size(), 'Should log 2 failed records');
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Batch Scope
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldRespectBatchSize() {
|
||||
@IsTest
|
||||
private static void shouldRespectBatchSize() {
|
||||
// Given
|
||||
List<Account> accounts = TestDataFactory.createAccounts(250, true);
|
||||
|
||||
@ -74,7 +74,7 @@ static void shouldRespectBatchSize() {
|
||||
|
||||
// Note: In tests, all batches execute but you can verify total processing
|
||||
List<Account> processed = [SELECT Id FROM Account WHERE Processed__c = true];
|
||||
System.assertEquals(250, processed.size(), 'All records should be processed');
|
||||
System.Assert.areEqual(250, processed.size(), 'All records should be processed');
|
||||
}
|
||||
```
|
||||
|
||||
@ -83,8 +83,8 @@ static void shouldRespectBatchSize() {
|
||||
### Basic Queueable Test
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldCompleteProcessing_WhenQueueableEnqueued() {
|
||||
@IsTest
|
||||
private static void shouldCompleteProcessing_WhenQueueableEnqueued() {
|
||||
// Given
|
||||
Account acc = TestDataFactory.createAccount(true);
|
||||
|
||||
@ -96,7 +96,7 @@ static void shouldCompleteProcessing_WhenQueueableEnqueued() {
|
||||
|
||||
// Then
|
||||
Account updated = [SELECT Id, Status__c FROM Account WHERE Id = :acc.Id];
|
||||
System.assertEquals('Processed', updated.Status__c,
|
||||
System.Assert.areEqual('Processed', updated.Status__c,
|
||||
'Queueable should update account status');
|
||||
}
|
||||
```
|
||||
@ -106,8 +106,8 @@ static void shouldCompleteProcessing_WhenQueueableEnqueued() {
|
||||
Chained queueables only execute the first job in tests:
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldChainNextJob_WhenMoreRecordsExist() {
|
||||
@IsTest
|
||||
private static void shouldChainNextJob_WhenMoreRecordsExist() {
|
||||
// Given: More records than one queueable can process
|
||||
List<Account> accounts = TestDataFactory.createAccounts(500, true);
|
||||
|
||||
@ -119,7 +119,7 @@ static void shouldChainNextJob_WhenMoreRecordsExist() {
|
||||
|
||||
// Verify first batch processed
|
||||
List<Account> processed = [SELECT Id FROM Account WHERE Processed__c = true];
|
||||
System.assertEquals(100, processed.size(), 'First batch should process 100 records');
|
||||
System.Assert.areEqual(100, processed.size(), 'First batch should process 100 records');
|
||||
|
||||
// Verify chain was enqueued (check AsyncApexJob)
|
||||
List<AsyncApexJob> jobs = [
|
||||
@ -127,15 +127,15 @@ static void shouldChainNextJob_WhenMoreRecordsExist() {
|
||||
FROM AsyncApexJob
|
||||
WHERE ApexClass.Name = 'MyChainedQueueable'
|
||||
];
|
||||
System.assert(jobs.size() >= 1, 'Chained job should be enqueued');
|
||||
System.Assert.isTrue(jobs.size() >= 1, 'Chained job should be enqueued');
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Queueable with Callouts
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldMakeCallout_WhenQueueableWithCallout() {
|
||||
@IsTest
|
||||
private static void shouldMakeCallout_WhenQueueableWithCallout() {
|
||||
// Given
|
||||
Test.setMock(HttpCalloutMock.class, new MockHttpResponse(200, '{"status":"ok"}'));
|
||||
Account acc = TestDataFactory.createAccount(true);
|
||||
@ -148,7 +148,7 @@ static void shouldMakeCallout_WhenQueueableWithCallout() {
|
||||
|
||||
// Then
|
||||
Account updated = [SELECT Id, External_Status__c FROM Account WHERE Id = :acc.Id];
|
||||
System.assertEquals('Synced', updated.External_Status__c,
|
||||
System.Assert.areEqual('Synced', updated.External_Status__c,
|
||||
'Should update status after successful callout');
|
||||
}
|
||||
```
|
||||
@ -156,8 +156,8 @@ static void shouldMakeCallout_WhenQueueableWithCallout() {
|
||||
## Future Method Testing
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldExecuteFutureMethod() {
|
||||
@IsTest
|
||||
private static void shouldExecuteFutureMethod() {
|
||||
// Given
|
||||
Account acc = TestDataFactory.createAccount(true);
|
||||
|
||||
@ -168,7 +168,7 @@ static void shouldExecuteFutureMethod() {
|
||||
|
||||
// Then
|
||||
Account updated = [SELECT Id, Processed__c FROM Account WHERE Id = :acc.Id];
|
||||
System.assertEquals(true, updated.Processed__c, 'Future should process record');
|
||||
System.Assert.areEqual(true, updated.Processed__c, 'Future should process record');
|
||||
}
|
||||
```
|
||||
|
||||
@ -177,8 +177,8 @@ static void shouldExecuteFutureMethod() {
|
||||
### Testing Scheduled Execution
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldExecuteScheduledJob() {
|
||||
@IsTest
|
||||
private static void shouldExecuteScheduledJob() {
|
||||
// Given
|
||||
List<Account> accounts = TestDataFactory.createAccounts(50, true);
|
||||
|
||||
@ -194,15 +194,15 @@ static void shouldExecuteScheduledJob() {
|
||||
|
||||
// Then
|
||||
List<Account> processed = [SELECT Id FROM Account WHERE Processed__c = true];
|
||||
System.assertEquals(50, processed.size(), 'Scheduled job should process records');
|
||||
System.Assert.areEqual(50, processed.size(), 'Scheduled job should process records');
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Schedule Registration
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldScheduleJob() {
|
||||
@IsTest
|
||||
private static void shouldScheduleJob() {
|
||||
Test.startTest();
|
||||
String cronExp = '0 0 6 * * ?'; // Daily at 6 AM
|
||||
String jobId = System.schedule('Daily Processing', cronExp, new MyScheduledClass());
|
||||
@ -214,16 +214,16 @@ static void shouldScheduleJob() {
|
||||
FROM CronTrigger
|
||||
WHERE Id = :jobId
|
||||
];
|
||||
System.assertEquals('0 0 6 * * ?', ct.CronExpression, 'CRON should match');
|
||||
System.assertEquals('WAITING', ct.State, 'Job should be waiting');
|
||||
System.Assert.areEqual('0 0 6 * * ?', ct.CronExpression, 'CRON should match');
|
||||
System.Assert.areEqual('WAITING', ct.State, 'Job should be waiting');
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Async Limits
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldNotExceedQueueableLimits() {
|
||||
@IsTest
|
||||
private static void shouldNotExceedQueueableLimits() {
|
||||
// Given: Setup that might enqueue multiple jobs
|
||||
List<Account> accounts = TestDataFactory.createAccounts(100, true);
|
||||
|
||||
@ -236,7 +236,7 @@ static void shouldNotExceedQueueableLimits() {
|
||||
Test.stopTest();
|
||||
|
||||
// Verify limit not exceeded (50 in synchronous context, 1 in queueable)
|
||||
System.assert(queueablesUsed <= 50,
|
||||
System.Assert.isTrue(queueablesUsed <= 50,
|
||||
'Should not exceed queueable limit. Used: ' + queueablesUsed);
|
||||
}
|
||||
```
|
||||
@ -252,7 +252,7 @@ System.enqueueJob(new MyQueueable());
|
||||
// Missing Test.stopTest()!
|
||||
|
||||
List<Account> results = [SELECT Id FROM Account WHERE Processed__c = true];
|
||||
System.assertEquals(100, results.size()); // FAILS - queueable didn't run
|
||||
System.Assert.areEqual(100, results.size()); // FAILS - queueable didn't run
|
||||
```
|
||||
|
||||
### ❌ Testing chained jobs without understanding limits
|
||||
|
||||
@ -7,7 +7,7 @@ Apex doesn't allow real HTTP callouts in tests. Use `HttpCalloutMock` interface.
|
||||
### Basic Mock Implementation
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
@IsTest
|
||||
public class MockHttpResponse implements HttpCalloutMock {
|
||||
|
||||
private Integer statusCode;
|
||||
@ -31,8 +31,8 @@ public class MockHttpResponse implements HttpCalloutMock {
|
||||
### Using the Mock
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldProcessApiResponse_WhenCalloutSucceeds() {
|
||||
@IsTest
|
||||
private static void shouldProcessApiResponse_WhenCalloutSucceeds() {
|
||||
// Given
|
||||
String mockResponse = '{"status": "success", "data": [{"id": "123"}]}';
|
||||
Test.setMock(HttpCalloutMock.class, new MockHttpResponse(200, mockResponse));
|
||||
@ -43,12 +43,12 @@ static void shouldProcessApiResponse_WhenCalloutSucceeds() {
|
||||
Test.stopTest();
|
||||
|
||||
// Then
|
||||
System.assertEquals(1, results.size(), 'Should parse one record from response');
|
||||
System.assertEquals('123', results[0].externalId, 'Should extract correct ID');
|
||||
System.Assert.areEqual(1, results.size(), 'Should parse one record from response');
|
||||
System.Assert.areEqual('123', results[0].externalId, 'Should extract correct ID');
|
||||
}
|
||||
|
||||
@isTest
|
||||
static void shouldHandleError_WhenCalloutFails() {
|
||||
@IsTest
|
||||
private static void shouldHandleError_WhenCalloutFails() {
|
||||
// Given
|
||||
String errorResponse = '{"error": "Unauthorized"}';
|
||||
Test.setMock(HttpCalloutMock.class, new MockHttpResponse(401, errorResponse));
|
||||
@ -59,8 +59,8 @@ static void shouldHandleError_WhenCalloutFails() {
|
||||
Test.stopTest();
|
||||
|
||||
// Then
|
||||
System.assertEquals(false, result.isSuccess, 'Should indicate failure');
|
||||
System.assert(result.errorMessage.contains('Unauthorized'), 'Should capture error');
|
||||
System.Assert.areEqual(false, result.isSuccess, 'Should indicate failure');
|
||||
System.Assert.isTrue(result.errorMessage.contains('Unauthorized'), 'Should capture error');
|
||||
}
|
||||
```
|
||||
|
||||
@ -69,7 +69,7 @@ static void shouldHandleError_WhenCalloutFails() {
|
||||
For services making multiple callouts:
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
@IsTest
|
||||
public class MultiRequestMock implements HttpCalloutMock {
|
||||
|
||||
private Map<String, HttpResponse> endpointResponses;
|
||||
@ -116,8 +116,8 @@ Test.setMock(HttpCalloutMock.class, new MultiRequestMock(mocks));
|
||||
For complex response bodies, store JSON in Static Resources:
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldParseComplexResponse() {
|
||||
@IsTest
|
||||
private static void shouldParseComplexResponse() {
|
||||
StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
|
||||
mock.setStaticResource('TestApiResponse'); // Static Resource name
|
||||
mock.setStatusCode(200);
|
||||
@ -129,7 +129,7 @@ static void shouldParseComplexResponse() {
|
||||
Result r = MyService.callExternalApi();
|
||||
Test.stopTest();
|
||||
|
||||
System.assertNotEquals(null, r, 'Should parse response');
|
||||
System.Assert.isNotNull(r, 'Should parse response');
|
||||
}
|
||||
```
|
||||
|
||||
@ -138,7 +138,7 @@ static void shouldParseComplexResponse() {
|
||||
For mocking Apex class dependencies using `System.StubProvider`:
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
@IsTest
|
||||
public class MyServiceMock implements System.StubProvider {
|
||||
|
||||
public Object handleMethodCall(
|
||||
@ -157,8 +157,8 @@ public class MyServiceMock implements System.StubProvider {
|
||||
}
|
||||
|
||||
// Usage in test:
|
||||
@isTest
|
||||
static void shouldUseAccountData() {
|
||||
@IsTest
|
||||
private static void shouldUseAccountData() {
|
||||
MyServiceMock mockProvider = new MyServiceMock();
|
||||
IMyService mockService = (IMyService)Test.createStub(IMyService.class, mockProvider);
|
||||
|
||||
@ -169,7 +169,7 @@ static void shouldUseAccountData() {
|
||||
String result = controller.displayAccountInfo();
|
||||
Test.stopTest();
|
||||
|
||||
System.assert(result.contains('Mock Account'), 'Should use mocked data');
|
||||
System.Assert.isTrue(result.contains('Mock Account'), 'Should use mocked data');
|
||||
}
|
||||
```
|
||||
|
||||
@ -178,8 +178,8 @@ static void shouldUseAccountData() {
|
||||
Apex sends real emails by default. Use limits to verify:
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldSendEmail_WhenTriggered() {
|
||||
@IsTest
|
||||
private static void shouldSendEmail_WhenTriggered() {
|
||||
Integer emailsBefore = Limits.getEmailInvocations();
|
||||
|
||||
Test.startTest();
|
||||
@ -187,7 +187,7 @@ static void shouldSendEmail_WhenTriggered() {
|
||||
Test.stopTest();
|
||||
|
||||
// Verify email was queued (not actually sent in tests)
|
||||
System.assertEquals(
|
||||
System.Assert.areEqual(
|
||||
emailsBefore + 1,
|
||||
Limits.getEmailInvocations(),
|
||||
'One email should be sent'
|
||||
@ -198,8 +198,8 @@ static void shouldSendEmail_WhenTriggered() {
|
||||
## Platform Event Testing
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
static void shouldPublishEvent_WhenRecordCreated() {
|
||||
@IsTest
|
||||
private static void shouldPublishEvent_WhenRecordCreated() {
|
||||
Test.startTest();
|
||||
|
||||
// Enable event delivery in test context
|
||||
@ -214,6 +214,6 @@ static void shouldPublishEvent_WhenRecordCreated() {
|
||||
|
||||
// Query platform event trigger results
|
||||
List<EventLog__c> logs = [SELECT Id FROM EventLog__c WHERE AccountId__c = :acc.Id];
|
||||
System.assertEquals(1, logs.size(), 'Event handler should create log record');
|
||||
System.Assert.areEqual(1, logs.size(), 'Event handler should create log record');
|
||||
}
|
||||
```
|
||||
|
||||
@ -7,7 +7,7 @@ TestDataFactory is a centralized utility class for creating test records with se
|
||||
## Base Template
|
||||
|
||||
```apex
|
||||
@isTest
|
||||
@IsTest
|
||||
public class TestDataFactory {
|
||||
|
||||
// ============ ACCOUNTS ============
|
||||
|
||||
Loading…
Reference in New Issue
Block a user