Hey guys so I’m having trouble with testing my scheduled apex class that is sending an email. The problem that is occurring for me is that when I click test, my System.assertEquals are not true meaning the job did not execute and the email did not send. Keep in mind that it works in my sandbox when I simply schedule it through the UI, but for my test class. It is not doing the same.

So my main question is, how do I execute my scheduled job in my test class? Here is the original class, and the test class.


global class Survey_Reminder implements Schedulable {
  public Static  String Chron= '0 35 11 ? 6 3';
global void execute(SchedulableContext ctx)
    List<test_sites__c> sitelist = [SELECT Name,Last_Survey_Date__c,Id FROM test_sites__c WHERE Status__c = 'Active'  AND  Last_Survey_Date__c <= :Date.Today().addDays(-30) AND Last_Survey_Date__c <= TODAY LIMIT 10];
    String sitestring= ' ';
    if(sitelist != null)
    for(test_sites__c site : sitelist)
         sitestring += site.Name + ' '; 
    } else
        sitestring = 'No sites to Report';
     Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddress = new String[] {'[email protected]'};
            mail.setSubject('Test Email');
            mail.setSenderDisplayName('Survey Reminder');
            mail.setPlainTextBody('Testing email  ' + sitestring);
            mail.setHtmlBody('<p>Testing email   </p> '+ sitestring);
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });



private class Reminder_Test {
    static testmethod void testScheduledJob()
    {List<test_sites__c> sites2 =  [SELECT Name FROM test_sites__c];
     Integer sitecount = sites2.size();
     System.debug('site count before insert: '+ sitecount);
        List<test_sites__c> sites = new List<test_sites__c>();
        Date survey =  Date.today().addDays(-30);
        for(integer i = 0; i<4; i++)
            test_sites__c site = new test_sites__c();
            site.Name = ' '+ i;
             site.Last_Survey_Date__c= survey;
        insert sites;
     sites2 =  [SELECT Name FROM test_sites__c];
      sitecount = sites2.size();
     System.debug('site count after insert: '+ sitecount);
        Survey_Reminder reminder = new Survey_Reminder();

       String Job = System.schedule('Test Rem', Survey_Reminder.Chron, reminder);
        integer beforeinvocations = Limits.getEmailInvocations();
        System.assertEquals(0,beforeinvocations,'no email sent');

        CronTrigger ct = [Select Id,CronExpression,TimesTriggered,NextFireTime FROM CronTrigger WHERE id = :Job];

        System.assertEquals(1, ct.TimesTriggered);
        System.assertEquals(1, beforeinvocations,'email sent');



1 Answer 1

    System.assertEquals(1, beforeinvocations,'email sent');

This won't be true for two reasons. First, you never checked Limits.getEmailInvocations() before the second assertion, and variables are not "live" or "reactive" in this sense; you need to get the value again. Second, the value would still be zero, because the class that invokes the email will be called before the governor limits are reset back to the testing limits. This means that all limit methods won't show things that happened during an asynchronous call, including Batchable, Queueable, future, and Schedulable.

I call this out in a previous answer.

You can keep track of if the class actually executed through a static @TestVisible variable in your class:

global class Survey_Reminder implements Schedulable {
  public Static  String Chron= '0 35 11 ? 6 3';
  @TestVisible static Integer emailLimitsUsed = 0;
  global void execute(SchedulableContext ctx) {
    // original code here //
    emailLimitsUsed = Limits.getEmailInvocations();

Which you can then check in your unit test:

System.assertEquals(1, Survey_Reminder.emailLimitsUsed,'email was not sent out');

Note that the third parameter should specify an error that describes what went wrong, not what you expected. I demonstrate this in the code above.

  • Ok, thanks for the information. but what about System.assertEquals(1, ct.TimesTriggered); ? this assert fails as well. which makes me assume that the job didn't execute at all. any tips on how to fix this? Commented Mar 16, 2021 at 15:28
  • @Apex_rookie If I remember correctly, it isn't updated until the transaction completes, so you can't actually see the change in a unit test. Set a static variable and check if that was updated; it's the most reliable way to tell when no records are updated/deleted/created otherwise.
    – sfdcfox
    Commented Mar 16, 2021 at 15:29
  • Ok, now that I think about it, that assert doesnt seem that useful now, since I'll know that the job has executed because of the email being sent right? anyway, thanks for the quick response! Commented Mar 16, 2021 at 15:36

Not the answer you're looking for? Browse other questions tagged .