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.
Best Answer
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...
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
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.