/** * @description Bulk testing template for trigger and service validation * Tests with 251+ records to ensure bulkification compliance. * 251 records crosses the 200-record trigger batch boundary. * @created {{Date}} */ @IsTest private class {{ClassName}}BulkTest { // Record counts for different test scenarios private static final Integer BULK_SIZE = 251; // Crosses 200-batch boundary private static final Integer LARGE_BULK_SIZE = 501; // Multiple batch boundaries private static final Integer SINGLE_BATCH = 200; // Single batch (edge case) // ═══════════════════════════════════════════════════════════════════════════ // BULK INSERT TESTS // ═══════════════════════════════════════════════════════════════════════════ /** * @description Tests bulk insert with 251 records * Verifies trigger handles multiple batch chunks correctly */ @IsTest static void testBulkInsert_251Records_AllProcessed() { // GIVEN List<{{ObjectName}}> records = TestDataFactory.create{{ObjectName}}s(BULK_SIZE); // WHEN Test.startTest(); Database.SaveResult[] results = Database.insert(records, false); Test.stopTest(); // THEN - All records should be successfully inserted Integer successCount = 0; Integer failCount = 0; for (Database.SaveResult sr : results) { if (sr.isSuccess()) { successCount++; } else { failCount++; System.debug('Insert failed: ' + sr.getErrors()[0].getMessage()); } } Assert.areEqual(BULK_SIZE, successCount, 'All ' + BULK_SIZE + ' records should insert successfully'); Assert.areEqual(0, failCount, 'No records should fail'); // Verify governor limits assertGovernorLimitsNotExceeded(); } /** * @description Tests bulk insert at exact batch boundary (200 records) */ @IsTest static void testBulkInsert_ExactBatchSize_AllProcessed() { // GIVEN List<{{ObjectName}}> records = TestDataFactory.create{{ObjectName}}s(SINGLE_BATCH); // WHEN Test.startTest(); insert records; Test.stopTest(); // THEN Integer count = [SELECT COUNT() FROM {{ObjectName}}]; Assert.areEqual(SINGLE_BATCH, count, 'All ' + SINGLE_BATCH + ' records should be inserted'); assertGovernorLimitsNotExceeded(); } // ═══════════════════════════════════════════════════════════════════════════ // BULK UPDATE TESTS // ═══════════════════════════════════════════════════════════════════════════ /** * @description Tests bulk update with 251 records * Verifies update triggers handle multiple batches */ @IsTest static void testBulkUpdate_251Records_AllUpdated() { // GIVEN - Insert records first List<{{ObjectName}}> records = TestDataFactory.create{{ObjectName}}s(BULK_SIZE); insert records; // Modify all records for ({{ObjectName}} rec : records) { // TODO: Update fields that trigger logic // rec.SomeField__c = 'Updated Value'; } // WHEN Test.startTest(); Database.SaveResult[] results = Database.update(records, false); Test.stopTest(); // THEN Integer successCount = 0; for (Database.SaveResult sr : results) { if (sr.isSuccess()) { successCount++; } } Assert.areEqual(BULK_SIZE, successCount, 'All ' + BULK_SIZE + ' records should update successfully'); assertGovernorLimitsNotExceeded(); } // ═══════════════════════════════════════════════════════════════════════════ // BULK DELETE TESTS // ═══════════════════════════════════════════════════════════════════════════ /** * @description Tests bulk delete with 251 records * Verifies delete triggers handle cleanup correctly */ @IsTest static void testBulkDelete_251Records_AllDeleted() { // GIVEN List<{{ObjectName}}> records = TestDataFactory.create{{ObjectName}}s(BULK_SIZE); insert records; // WHEN Test.startTest(); Database.DeleteResult[] results = Database.delete(records, false); Test.stopTest(); // THEN Integer successCount = 0; for (Database.DeleteResult dr : results) { if (dr.isSuccess()) { successCount++; } } Assert.areEqual(BULK_SIZE, successCount, 'All ' + BULK_SIZE + ' records should delete successfully'); Integer remainingCount = [SELECT COUNT() FROM {{ObjectName}}]; Assert.areEqual(0, remainingCount, 'No records should remain'); } // ═══════════════════════════════════════════════════════════════════════════ // MIXED DML BULK TESTS // ═══════════════════════════════════════════════════════════════════════════ /** * @description Tests mixed operations in bulk * Verifies partial success scenarios are handled */ @IsTest static void testBulkMixedOperations_PartialSuccess() { // GIVEN - Some valid, some invalid records List<{{ObjectName}}> validRecords = TestDataFactory.create{{ObjectName}}s(200); List<{{ObjectName}}> invalidRecords = new List<{{ObjectName}}>(); // Create invalid records (missing required fields or validation failures) for (Integer i = 0; i < 51; i++) { invalidRecords.add(new {{ObjectName}}( // TODO: Set up record that will fail validation )); } List<{{ObjectName}}> allRecords = new List<{{ObjectName}}>(); allRecords.addAll(validRecords); allRecords.addAll(invalidRecords); // WHEN - Insert with allOrNone = false Test.startTest(); Database.SaveResult[] results = Database.insert(allRecords, false); Test.stopTest(); // THEN - Count successes and failures Integer successCount = 0; Integer failCount = 0; for (Database.SaveResult sr : results) { if (sr.isSuccess()) { successCount++; } else { failCount++; } } // Verify partial success handled correctly Assert.isTrue(successCount > 0, 'Some records should succeed'); // Note: Uncomment if you expect failures // Assert.isTrue(failCount > 0, 'Some records should fail validation'); } // ═══════════════════════════════════════════════════════════════════════════ // GOVERNOR LIMIT VERIFICATION // ═══════════════════════════════════════════════════════════════════════════ /** * @description Helper method to verify governor limits not exceeded * Call after Test.stopTest() to check limit usage */ private static void assertGovernorLimitsNotExceeded() { // SOQL Queries (limit: 100) Assert.isTrue(Limits.getQueries() < 90, 'SOQL queries approaching limit: ' + Limits.getQueries() + '/100'); // DML Statements (limit: 150) Assert.isTrue(Limits.getDmlStatements() < 140, 'DML statements approaching limit: ' + Limits.getDmlStatements() + '/150'); // DML Rows (limit: 10,000) Assert.isTrue(Limits.getDmlRows() < 9500, 'DML rows approaching limit: ' + Limits.getDmlRows() + '/10000'); // Heap Size (limit: 6MB sync, 12MB async) Assert.isTrue(Limits.getHeapSize() < 5000000, 'Heap size approaching limit: ' + Limits.getHeapSize() + '/6000000'); // CPU Time (limit: 10,000ms sync, 60,000ms async) Assert.isTrue(Limits.getCpuTime() < 9000, 'CPU time approaching limit: ' + Limits.getCpuTime() + '/10000'); System.debug('═══════════════════════════════════════════════════════'); System.debug('GOVERNOR LIMIT USAGE:'); System.debug(' SOQL Queries: ' + Limits.getQueries() + '/100'); System.debug(' DML Statements: ' + Limits.getDmlStatements() + '/150'); System.debug(' DML Rows: ' + Limits.getDmlRows() + '/10000'); System.debug(' Heap Size: ' + Limits.getHeapSize() + '/6000000'); System.debug(' CPU Time: ' + Limits.getCpuTime() + 'ms /10000ms'); System.debug('═══════════════════════════════════════════════════════'); } // ═══════════════════════════════════════════════════════════════════════════ // STRESS TESTS (Optional - Run sparingly) // ═══════════════════════════════════════════════════════════════════════════ /** * @description Stress test with 501 records (multiple batch boundaries) * Use sparingly - consumes significant test execution time */ @IsTest static void testStressTest_501Records_AllProcessed() { // GIVEN List<{{ObjectName}}> records = TestDataFactory.create{{ObjectName}}s(LARGE_BULK_SIZE); // WHEN Test.startTest(); insert records; Test.stopTest(); // THEN Integer count = [SELECT COUNT() FROM {{ObjectName}}]; Assert.areEqual(LARGE_BULK_SIZE, count, 'All ' + LARGE_BULK_SIZE + ' records should be processed'); assertGovernorLimitsNotExceeded(); } }