Intermediate 25 min read

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();
    }
}
  1. @isTest — marks the test class.
  2. private class LeaveRequestOverlapTest { — the class.
  3. @isTest — marks the test method.
  4. static void overlappingRequestAgainstAnExistingApprovedRequestIsBlocked() { — a clearly-named test.
  5. insert new Leave_Request__c( — an already-approved existing request.
  6. Employee_Name__c = 'Amara', Start_Date__c = Date.newInstance(2026, 4, 1), — the employee and start date.
  7. End_Date__c = Date.newInstance(2026, 4, 5), Status__c = 'Approved' — the end date and status.
  8. ); — closes the constructor call.
  9. (blank line)
  10. Test.startTest(); — marks the start of the action being tested.
  11. try { — this is exactly Module 26's "Test the Feature" pattern — plus a try/catch around the expected DmlException.
  12. insert new Leave_Request__c( — a new, overlapping request.
  13. Employee_Name__c = 'Amara', Start_Date__c = Date.newInstance(2026, 4, 3), — the same employee, overlapping dates.
  14. End_Date__c = Date.newInstance(2026, 4, 10), Status__c = 'Pending' — the rest of the fields.
  15. ); — closes the constructor call.
  16. 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.
  17. } catch (DmlException e) { — catches the expected failure.
  18. System.assert(e.getMessage().contains('overlap'), 'Expected the error to mention the overlap'); — verifies it's the right error, not some unrelated failure.
  19. } — closes the catch.
  20. Test.stopTest(); — marks the end.
  21. } — closes the test method.
  22. } — 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();
    }
}
  1. @isTest — marks the class.
  2. private class LeaveRequestOverlapTest { — the same test class as before.
  3. // ... overlappingRequestAgainstAnExistingApprovedRequestIsBlocked() from above ... — the first test method still lives here too.
  4. (blank line)
  5. @isTest — marks a second test method.
  6. static void overlappingRequestsInTheSameBatchAreBlocked() { — a clearly-named test for the batch scenario.
  7. List<Leave_Request__c> batch = new List<Leave_Request__c>{ — two requests submitted together.
  8. 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.
  9. 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.
  10. }; — closes the list literal.
  11. (blank line)
  12. Test.startTest(); — marks the start.
  13. 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.
  14. insert batch; — inserts both at once.
  15. System.assert(false, 'Expected this overlapping batch to be blocked'); — should never be reached.
  16. } catch (DmlException e) { — catches the expected failure.
  17. System.assert(e.getMessage().contains('overlap'), 'Expected the error to mention the overlap'); — verifies the right error.
  18. } — closes the catch.
  19. Test.stopTest(); — marks the end.
  20. } — closes the test method.
  21. } — 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.

APEX

Test with Multiple Records Quiz

1. Why would testing only single-record inserts miss a real bug in this feature?

Log in to submit the quiz and save your score.

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.