Test with Multiple Records
By the end of this lesson, you'll be able to:
- Write @isTest methods covering both overlap scenarios
- Test a batch insert with multiple records at once, not just one record at a time
- Recognize why testing only single-record scenarios would miss real bugs here
Prerequisites: "Bulkify the Logic"
Verifying against an existing record
@isTest
private class LeaveRequestOverlapTest {
@isTest
static void overlappingRequestAgainstAnExistingApprovedRequestIsBlocked() {
insert new Leave_Request__c(
Employee_Name__c = 'Amara', Start_Date__c = Date.newInstance(2026, 4, 1),
End_Date__c = Date.newInstance(2026, 4, 5), Status__c = 'Approved'
);
Test.startTest();
try {
insert new Leave_Request__c(
Employee_Name__c = 'Amara', Start_Date__c = Date.newInstance(2026, 4, 3),
End_Date__c = Date.newInstance(2026, 4, 10), Status__c = 'Pending'
);
System.assert(false, 'Expected this overlapping request to be blocked');
} catch (DmlException e) {
System.assert(e.getMessage().contains('overlap'), 'Expected the error to mention the overlap');
}
Test.stopTest();
}
}
@isTest— marks the test class.private class LeaveRequestOverlapTest {— the class.@isTest— marks the test method.static void overlappingRequestAgainstAnExistingApprovedRequestIsBlocked() {— a clearly-named test.insert new Leave_Request__c(— an already-approved existing request.Employee_Name__c = 'Amara', Start_Date__c = Date.newInstance(2026, 4, 1),— the employee and start date.End_Date__c = Date.newInstance(2026, 4, 5), Status__c = 'Approved'— the end date and status.);— closes the constructor call.- (blank line)
Test.startTest();— marks the start of the action being tested.try {— this is exactly Module 26's "Test the Feature" pattern — plus atry/catcharound the expectedDmlException.insert new Leave_Request__c(— a new, overlapping request.Employee_Name__c = 'Amara', Start_Date__c = Date.newInstance(2026, 4, 3),— the same employee, overlapping dates.End_Date__c = Date.newInstance(2026, 4, 10), Status__c = 'Pending'— the rest of the fields.);— closes the constructor call.System.assert(false, 'Expected this overlapping request to be blocked');— if this line is ever reached, the insert should have thrown but didn't — fail the test.} catch (DmlException e) {— catches the expected failure.System.assert(e.getMessage().contains('overlap'), 'Expected the error to mention the overlap');— verifies it's the right error, not some unrelated failure.}— closes thecatch.Test.stopTest();— marks the end.}— closes the test method.}— closes the class.
Wrapped in @isTest, this verifies the new-vs-existing overlap check automatically, every time, instead of by hand.
Verifying a batch insert — the scenario a single-record test can't catch
@isTest
private class LeaveRequestOverlapTest {
// ... overlappingRequestAgainstAnExistingApprovedRequestIsBlocked() from above ...
@isTest
static void overlappingRequestsInTheSameBatchAreBlocked() {
List<Leave_Request__c> batch = new List<Leave_Request__c>{
new Leave_Request__c(Employee_Name__c = 'Ben', Start_Date__c = Date.newInstance(2026, 5, 1), End_Date__c = Date.newInstance(2026, 5, 5), Status__c = 'Pending'),
new Leave_Request__c(Employee_Name__c = 'Ben', Start_Date__c = Date.newInstance(2026, 5, 3), End_Date__c = Date.newInstance(2026, 5, 8), Status__c = 'Pending')
};
Test.startTest();
try {
insert batch;
System.assert(false, 'Expected this overlapping batch to be blocked');
} catch (DmlException e) {
System.assert(e.getMessage().contains('overlap'), 'Expected the error to mention the overlap');
}
Test.stopTest();
}
}
@isTest— marks the class.private class LeaveRequestOverlapTest {— the same test class as before.// ... overlappingRequestAgainstAnExistingApprovedRequestIsBlocked() from above ...— the first test method still lives here too.- (blank line)
@isTest— marks a second test method.static void overlappingRequestsInTheSameBatchAreBlocked() {— a clearly-named test for the batch scenario.List<Leave_Request__c> batch = new List<Leave_Request__c>{— two requests submitted together.new Leave_Request__c(Employee_Name__c = 'Ben', Start_Date__c = Date.newInstance(2026, 5, 1), End_Date__c = Date.newInstance(2026, 5, 5), Status__c = 'Pending'),— the first.new Leave_Request__c(Employee_Name__c = 'Ben', Start_Date__c = Date.newInstance(2026, 5, 3), End_Date__c = Date.newInstance(2026, 5, 8), Status__c = 'Pending')— the second, overlapping the first.};— closes the list literal.- (blank line)
Test.startTest();— marks the start.try {— testing only single-record inserts (one at a time) would never exercise Lesson 4's new-vs-new comparison at all — that logic only ever runs when multiple records are inserted together in the same transaction.insert batch;— inserts both at once.System.assert(false, 'Expected this overlapping batch to be blocked');— should never be reached.} catch (DmlException e) {— catches the expected failure.System.assert(e.getMessage().contains('overlap'), 'Expected the error to mention the overlap');— verifies the right error.}— closes thecatch.Test.stopTest();— marks the end.}— closes the test method.}— closes the class.
This is exactly why "test with multiple records" earns its own dedicated test method rather than being folded into the single-record test.
Exercise
Add a third test method, nonOverlappingBatchInsertsSucceed, that inserts a batch of 2 non-overlapping requests for the same employee and asserts no exception is thrown.
Show hint
Use dates that clearly don't overlap, e.g. one in March, one in June — no try/catch needed if you don't expect an exception.
Test with Multiple Records 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 verifies the feature specifically with multi-record batches — a single-record test would never catch a new-vs-new overlap bug, since that scenario only exists at the batch level.