1

I have set a schedule class which checks for running or queued batches. If there are more than 5 batches running then it gets execute after 30 min delay. But I am not able to cover the else part in test coverage. If any body can help me in this regard it would be a great help. Below is my code.

New modified class as per crop1645 suggested below : global class LeadReminderSchedule implements Schedulable{

list<Lead> schedule = new list<Lead>(); 

IAsyncJob iGetJobs = new GetProdJobs();  // default to prod interface
//AsyncJob iTestGetJobs = new GetTestJobs();
// Interfaces and their implementation - prod vs test
public interface IAsyncJob {
    list<AsyncApexJob> getJobs();
}

public class GetProdJobs implements IAsyncJob {
    public list<AsyncApexJob> getJobs() {
        return [select id FROM AsyncApexJob WHERE JobType='BatchApex' AND (Status = 'Processing' OR Status = 'Preparing' OR Status = 'Queued')];  
    }
}

public class abc implements IAsyncJob {
    public list<AsyncApexJob> getJobs() {
        list<AsyncApexJob> res = new list<AsyncApexJob>();
        for (Integer i = 0; i < 6; i++)  
            res.add(new AsyncApexJob());
        return res;
    }
}

global void execute(SchedulableContext ctx)
{
    try{
        CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime
                                 FROM CronTrigger 
                                 WHERE 
                                 Id = :ctx.getTriggerId()];

        system.debug('--cron expression--'+ct.CronExpression);
        system.debug('-cron trigger run--'+ ct.TimesTriggered);

        LeadReminderMail lrm = new LeadReminderMail();
        lrm.sendMail();

        LeadReminderBatchSMS lrbs = new LeadReminderBatchSMS();

        Integer scopeSize =100;

         if (iGetJobs.getJobs().size()< 5){ 
            Database.executeBatch(lrbs);
         } else {
            //schedule this same schedulable class again in 30 mins

            LeadReminderSchedule lrs = new LeadReminderSchedule();
            Datetime dt = Datetime.now() + (0.024305); // i.e. 30 mins
            String timeForScheduler = dt.format('s m H d M \'?\' yyyy');
            Id schedId = System.Schedule('MatrixRetry'+timeForScheduler,timeForScheduler,lrs);

            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddresses = new String[] {'rohit.k@bmcgroup.in'};
            mail.setToAddresses(toAddresses);
            mail.setSubject('Lead: Reminder Batch Scheduled for later execution' );
            mail.setPlainTextBody
            ('The batch Apex job will be processed at' + dt +
                '. As No. of batches in process are more than 5');
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        }

        //cleaning(); // to clean deleted or aborted schedule jobs.

    }catch(exception ex){
        system.debug('--Exception is--'+ ex.getMessage());
    }
}

What to add in below test class to cover the else part also (modified):

@isTest
 private class TestLeadReminderSchedule {

public interface IAsyncJob {
        List<AsyncApexJob> getJobs();
}
static testMethod void myUnitTest() {
   test.startTest();
   LeadReminderSchedule lrs = new LeadReminderSchedule();
   String schedule = '0 0 23 * * ?';
   system.schedule('Daily Schedule' , schedule, lrs);
   test.stopTest();
}

static testMethod void myLimitAvoidanceUnitTest() { 
    test.startTest();
    LeadReminderSchedule lrs = new LeadReminderSchedule();
    ***lrs.iGetJobs = new TheOuterClassName.GetTestJobs();***  // will return > 5 asyncjobs and execute your else condition
    String schedule = '0 0 23 * * ?';
    system.schedule('Daily Schedule' , schedule, lrs);
    test.stopTest();

}

}

Above error (Compilation error: Invalid type: TheOuterClassName.GetTestJobs) is coming on this line, in test class : lrs.iGetJobs = new TheOuterClassName.GetTestJobs() What to do.

2

Because you can't execute more than one Batch in a testmethod, and, you can't insert AsyncApexJob SObjects in testmethods, you could ...

You could add to your class...

IAsyncJob iGetJobs = new GetProdJobs();  // default to prod interface

 // Interfaces and their implementation - prod vs test
 public interface IAsyncJob {
   List<AsyncApexJob> getJobs();
 }

 public class GetProdJobs implements IAsyncJob {
   public List<AsyncApexJob> getJobs() {
       return [select id FROM AsyncApexJob WHERE JobType='BatchApex' AND (Status = 'Processing' OR Status = 'Preparing' OR Status = 'Queued')];  
   }
 }

 public class GetTestJobs implements IAsyncJob {
    public List<AsyncApexJob> getJobs() {
         List<AsyncApexJob> res = new List<AsyncApexJob> ();
         for (Integer i = 0; i < 6; i++)  
             res.add(new AsyncApexJob());
        return res;
    }
 }

// your logic up to the if statement ...

 if (iGetJobs.getJobs().size()< 5){ 
        Database.executeBatch(lrbs);
    } else {
        //schedule this same schedulable class again in 30 mins
    ....

Then, create two testmethods - one to test the (default) prod interface and one to test the > 5 jobs use case. You already have the first. here's the second

static testMethod void myLimitAvoidanceUnitTest() {
   test.startTest();
   LeadReminderSchedule lrs = new LeadReminderSchedule();
   lrs.iGetJobs = new TheOuterClassName.GetTestJobs();  // will return > 5 asyncjobs and execute your else condition
   String schedule = '0 0 23 * * ?';
   system.schedule('Daily Schedule' , schedule, lrs);
   test.stopTest();
}

There are a couple of other options:

Now, as I mentioned in the comment to the OP, the Appleman pattern avoids this whole limits avoidance routine and is highly recommended.

You could also move all your else logic into a separate method and test that method explicitly to see if it does what you expect to get test coverage

Note - I didn't test the above code as I borrowed it from other working samples and edited it to your use case.

  • I am getting the compile error: invalid type- GetTestJobs() in test class. I have tried this : IAsyncJob iGetJobs = new GetTestJobs(); . Tried many other things but not able to rectify it but same error is coming. Can you please help me. – Rohit Nov 14 '14 at 9:51
  • Rohit -- I changed the line to reference the outerclassname (you'll have to supply the real name: lrs.iGetJobs = new TheOuterClassName.GetTestJobs(); – cropredy Nov 14 '14 at 17:14
  • same error is coming crop1645 : Compilation error: Invalid type: TheOuterClassName.GetTestJobs. Please let me know if any thing else you can suggest. – Rohit Nov 17 '14 at 11:54
  • Rohit -- replace TheOuterClassName with the name of your outer class: LeadReminderSchedule – cropredy Nov 17 '14 at 20:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.