I’ve setup some chain execution batch classes. For this setup we decided to chain the batch classes through schedulable classes. We thought it might be a good idea to include a check for 5 batch jobs running so we didn’t hit the concurrent batch processing limit. Here’s the method we put into our schedulable classes:
global class Schedule_Batch implements Schedulable { global void execute(SchedulableContext sc) { MyBatch b = new MyBatch(); //check if there are 5 active batch jobs if([Select count() FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')]<5){ Database.executebatch(b); }else{ //schedule this same class again in 30 minutes Schedule_Batch bagain = new Schedule_Batch(); Datetime dt = Datetime.now() + (0.024305); // i.e. 30 mins String timeForScheduler = dt.format('s m H d M '?' yyyy'); Id schedId = system.Schedule('CFP_TaskBatch_Retry'+timeForScheduler,timeForScheduler,bagain); } } }
This was taken from the developer forums – http://help.salesforce.com/apex/HTViewSolution?id=000182449&language=en_US.
The problem is unit testing. I’ve not been able to get to the else part of the if statement that finds at least five concurrent jobs running. Would someone please help me to test out 5 concurrent batch jobs running so I can have full coverage for the schedulable class? Here’s the relevant part of my test class that I’m trying so far:
MyBatch b = new MyBatch(); Id BatchprocessId = Database.executeBatch(b); MyBatch b2 = new MyBatch(); Id BatchprocessId2 = Database.executeBatch(b2); MyBatch b3 = new MyBatch(); Id BatchprocessId3 = Database.executeBatch(b3); MyBatch b4 = new MyBatch(); Id BatchprocessId4 = Database.executeBatch(b4); MyBatch b5 = new MyBatch(); Id BatchprocessId5 = Database.executeBatch(b5); Schedule_Batch q = new Schedule_Batch(); SchedulableContext scq; q.execute(scq);
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You’re going to have to fake it. What I do in situations like this is create a property with a getter and setter, but where the setter can only be used in tests.
As an example, setup a new property:
public static Integer runningJobCount{ get{ if(runningJobCount == null) return [Select count() FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')]; else return runningJobCount; } set{ System.assert(Test.isRunningTest(),'This property may only be set in tests'); runningJobCount = value; } }
Then change this line:
if([Select count() FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')]<5){
to
if(runningJobCount <5){
Then in your test you can set *Schedule_Batch.runningJobCount = 5;* in the test you want to test this scenario.
Method 2
One thing I would add to the answer above – I prefer to store the max batches variable (5 in the answer above) in a custom setting for two reasons:
- You can then set it differently for different tests
- 5 might be too high at some point – I have seen several packages/implementations that require a batch to be running most of the time – so in that circumstance, you would probably want your check to be able to leave at at least one batch queue available…having it in a setting makes it easier to adjust on the fly…
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0