Write a Full Test Suite
By the end of this lesson, you'll be able to:
- Write bulk-safe test coverage for both triggers and the batch job
- Test the overdraft-rejection and frozen-account scenarios explicitly
- Apply Module 31's testing principles to a system with real financial stakes
Prerequisites: "Secure Account Data"
Testing the happy path in bulk
@isTest
private class TransactionTriggerTest {
@isTest
static void updatesBalanceForBulkDeposits() {
Bank_Account__c acc = new Bank_Account__c(Name = 'Test', Balance__c = 0, Status__c = 'Active');
insert acc;
List<Transaction__c> deposits = new List<Transaction__c>();
for (Integer i = 0; i < 200; i++) {
deposits.add(new Transaction__c(Bank_Account__c = acc.Id, Type__c = 'Deposit', Amount__c = 10));
}
Test.startTest();
insert deposits;
Test.stopTest();
Assert.areEqual(2000, [SELECT Balance__c FROM Bank_Account__c WHERE Id = :acc.Id].Balance__c);
}
}
200 deposits of 10 each should net to exactly 2000 — this is Module 31's "always test at bulk scale" rule, catching any hidden per-record assumption Lesson 2's trigger might have.
Testing the rejection paths explicitly
@isTest
static void rejectsOverdraftWithdrawal() {
Bank_Account__c acc = new Bank_Account__c(Name = 'Test', Balance__c = 100, Status__c = 'Active');
insert acc;
Transaction__c overdraft = new Transaction__c(Bank_Account__c = acc.Id, Type__c = 'Withdrawal', Amount__c = 500);
Test.startTest();
try {
insert overdraft;
Assert.fail('Expected an overdraft DmlException');
} catch (DmlException e) {
Assert.isTrue(e.getMessage().contains('Insufficient funds'));
}
Test.stopTest();
}
This is Module 31's negative-path testing principle — confirming the rejection itself works correctly is just as important as confirming a valid deposit updates the balance, since an untested rejection path could silently let an overdraft through.
Testing the async ledger callout with a mock
@isTest
static void reportsToLedgerAsynchronously() {
Test.setMock(HttpCalloutMock.class, new LedgerMockSuccess());
Bank_Account__c acc = new Bank_Account__c(Name = 'Test', Balance__c = 0, Status__c = 'Active');
insert acc;
Test.startTest();
insert new Transaction__c(Bank_Account__c = acc.Id, Type__c = 'Deposit', Amount__c = 50);
Test.stopTest(); // forces the enqueued Queueable job to run synchronously here
// assert on a field the mock's callout would have set, or that no exception occurred
}
Test.setMock and Test.stopTest() forcing the enqueued job to run are Module 31's and Module 36's exact async-callout testing patterns, combined here for the ledger-integration job from Lesson 4.
Exercise
As a comment, list the three categories of test this lesson covers, and why all three are needed rather than just the happy-path bulk test.
Show hint
Think about what each test type would catch that the others wouldn't.
Write a Full Test Suite Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
This lesson applies Module 31's full testing toolkit — bulk data, negative-path testing, and Test.startTest()/stopTest() for the async ledger callout — to a system where an untested edge case has real financial consequences.