Adding a Test for the Schedulable Class

Schedule Apex:
------------------------------------------------------------------------------------------------------------------
global class MySchedulableClass implements Schedulable 
 {     
   global void execute(SchedulableContext ctx) 
       {        
          CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime  FROM CronTrigger WHERE Id = :ctx.getTriggerId()];   
          System.debug(ct.CronExpression);        
          System.debug(ct.TimesTriggered);        
          Merchandise__c m = new Merchandise__c(Name='Scheduled Job Item', Description__c='Created by the scheduler',Price__c=1,Total_Inventory__c=1000);
          insert m;     
         }     
   }
-------------------------------------------------------------------------
Test Class:
-------------------------------------------------
@isTest  private class TestSchedulableClass 
{       // CRON expression: midnight on March 15.
     // Because this is a test, job executes     
// immediately after Test.stopTest().     
 public static String CRON_EXP = '0 0 0 15 3 ? 2022'; 
 static testmethod void test() 
    {        
        Test.startTest();          
       // Schedule the test job     
          String jobId = System.schedule('ScheduleApexClassTest', CRON_EXP, new MySchedulableClass());
        // Get the information from the CronTrigger API object        
          CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime    FROM CronTrigger WHERE id = :jobId];     
     // Verify the expressions are the same        
      System.assertEquals(CRON_EXP,ct.CronExpression);  
        // Verify the job has not run        
       System.assertEquals(0, ct.TimesTriggered);       
    // Verify the next time the job will run       
      System.assertEquals('2022-03-15 00:00:00',String.valueOf(ct.NextFireTime));  
      // Verify the scheduled job hasn't run yet.      
       Merchandise__c[] ml = [SELECT Id FROM Merchandise__c  WHERE Name = 'Scheduled Job Item'];   
     System.assertEquals(ml.size(),0);        
      Test.stopTest();          
// Now that the scheduled job has executed after Test.stopTest(),    
    //   fetch the new merchandise that got added.       
 ml = [SELECT Id FROM Merchandise__c   WHERE Name = 'Scheduled Job Item'];
        System.assertEquals(ml.size(), 1);       
      }  
}
---------------------------------------------------------    

Tell Me More...
  • The test method schedules the MySchedulableClass class by calling the System.schedule method. The System.Schedulemethod takes three arguments: a name for the job, an expression used to represent the time and date the job is scheduled to run, and the name of the class. The System.schedule method uses the user's timezone for the basis of all schedules.
  • The call to System.schedule is included within the Test.startTest and Test.stopTest block. This ensures that the job gets executed after the Test.stopTest call regardless of the schedule specified in the cron expression. Any asynchronous code included within Test.startTest and Test.stopTest gets executed synchronously afterTest.stopTest.
  • You can only have 100 classes scheduled at one time.
  • If we are executing a batch class in schedule class's execute methods we might not get that result after Test.stopTest

Execution Failed: System.TypeException: Cannot have more than 10 chunks in a single operation. Please rearrange the data to reduce chunking.

The order of the items seems to play a part in the 'chunking'. It chunks everytime you switch object types. If you are passing 12 items in a list of types A and B, this list contains 2 chunks:

A, A, A, A, A, A, B, B, B, B, B, B 

But this list contains 12 chunks:

A, B, A, B, A, B, A, B, A, B, A, B


When we executes following code

1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
List<SObject> toSave = new List<SObject>();
for(integer i = 0; i < 100; i++ )
{
    BB_A__c bba = new BB_A__c(
        x__c = 'testx',
        y__c = 'testy'
    );
    if(i == 5)
    {
        bba.x__c = 'bartek';
    }
    toSave.add(bba);
     
    BB_B__c bbb = new BB_B__c(
        x__c = 'testx',
        y__c = 'testy'
    );
    if(i == 7)
    {
        bba.y__c = 'bartek';
    }
    toSave.add(bbb);   
}
insert toSave;

We receive following error:
Execution Failed. System.TypeException: Cannot have more than 10 chunks in a single operation. Please rearrange the data to reduce chunking.

but after execution of this script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
List<SObject> toSave = new List<SObject>();
for(integer i = 0; i < 100; i++ )
{
    BB_A__c bba = new BB_A__c(
        x__c = 'testx',
        y__c = 'testy'
    );
    if(i == 5)
    {
        bba.x__c = 'bartek';
    }
    toSave.add(bba);
}
 
for(integer i = 0; i < 100; i++ )
{  
    BB_B__c bbb = new BB_B__c(
        x__c = 'testx',
        y__c = 'testy'
    );
    if(i == 7)
    {
        bbb.y__c = 'bartek';
    }
    toSave.add(bbb);
     
}
insert toSave;

everything goes smoothly. This is because when you insert list with multiple object, data type cannot change more than 10 times. Do not ask why, this is SALESFORCE.
But there is a simple solution:
You have to sort the list that you want to add. Because standard List.sort() method sorts collection by SObject labels then you will have all objects grouped by SObject label that is equals to sobject type:). Here is a working example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
List<SObject> toSave = new List<SObject>();
for(integer i = 0; i < 100; i++ )
{
    BB_A__c bba = new BB_A__c(
        x__c = 'testx',
        y__c = 'testy'
    );
    if(i == 5)
    {
        bba.x__c = 'bartek';
    }
    toSave.add(bba);
     
    BB_B__c bbb = new BB_B__c(
        x__c = 'testx',
        y__c = 'testy'
    );
    if(i == 7)
    {
        bba.y__c = 'bartek';
    }
    toSave.add(bbb);
     
}
 
toSave.sort(); // <-- this line fixes our issue:):):)
 
insert toSave;

Counters