You need to sign in to do that
Don't have an account?
dwright01
How to test scheduled apex that executes a batch job
I wrote some apex and would like to write a test for it, but am stumped as to how to do it!
The code to be tested is an apex "after update" trigger that schedules some apex code to run in 2 seconds, and this code in turn starts a batch job. The job runs execute() and finish(), and I want my test code to verify that the execute() and finish() did the right the right things.
The test code is like this:
<create records>
Test.startTest();
update acct;
Test.stopTest();
<asserts that the execute and finish code did the right things>
But, through use of logging, I see that the scheduled apex code ran fine, and started the batch job, but the execute() and finish() code happens after my asserts and the test routine finishes! This is not at all what I expected would happen from reading the documentation. It is good (for coverage) that the code runs, but m test is not able to assert that the code worked.
I cannot figure out how to write the test to verify that the actions the trigger did, including running the batch job, worked correctly.
The only thing I can think of is to write a separate test simulating the scheduled apex code itself.
Anyone else have any ideas?
Thanks, Dave
The code to be tested is an apex "after update" trigger that schedules some apex code to run in 2 seconds, and this code in turn starts a batch job. The job runs execute() and finish(), and I want my test code to verify that the execute() and finish() did the right the right things.
The test code is like this:
<create records>
Test.startTest();
update acct;
Test.stopTest();
<asserts that the execute and finish code did the right things>
But, through use of logging, I see that the scheduled apex code ran fine, and started the batch job, but the execute() and finish() code happens after my asserts and the test routine finishes! This is not at all what I expected would happen from reading the documentation. It is good (for coverage) that the code runs, but m test is not able to assert that the code worked.
I cannot figure out how to write the test to verify that the actions the trigger did, including running the batch job, worked correctly.
The only thing I can think of is to write a separate test simulating the scheduled apex code itself.
Anyone else have any ideas?
Thanks, Dave
I opened a case to Salesforce Support asking about this. The support person tested it and discussed with the dev team. It is working as designed, but he agreed that it would be better if all the asynch processed thar would be run as a result of the code after startTest() actually were completed by the time stopTest() returned. He was going to request that this functionality be implemented in a future release.
All Answers
Ok you can see the problem by creating the following 3 classes:
---
@isTest
private class testScheduledClassThatStartsBatchJob{
static testMethod void myTest() {
Account acct = new Account(Name = 'Some Account');
insert acct;
Test.startTest();
System.debug('*** startTest called');
SchedulableApexBatch.CallExecuteMomentarily();
Test.stopTest();
System.debug('*** stopTest called');
}
}
----------------------------------
global class SchedulableApexBatch Implements Schedulable {
// This is called when the scheduled task runs. It finds the first ApexBatch__c record to be processed and schedules a batch
// job to run it if we find one and the job is not scheduled or running.
global void Execute(SchedulableContext ctx) {
Database.executeBatch(new BatchClass());
}
// return a Cron expression to schedule the job at a specific time
private static String GetSchedulerExpression(DateTime dt) {
return '' + dt.second() + ' ' + dt.minute() + ' ' + dt.hour() + ' ' + dt.day() + ' ' + dt.month() + ' ? ' + dt.year();
}
public static void CallExecuteMomentarily() {
System.schedule('ScheduledApexBatch',
GetSchedulerExpression(DateTime.Now().addSeconds(2)),
new SchedulableApexBatch());
}
}
-------------------------------------
global class BatchClass implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT id FROM Account');
}
global void execute(Database.BatchableContext BC, List<sObject> scope) {
// delegate the execution of this context
System.debug('*** execute');
}
// finish the job. Stores status of this job, then if there is another general batch job queued up, schedule it
global void finish(Database.BatchableContext BC) {
System.debug('*** finish');
}
}
--------------------------------------
Turn on debugging, and run the test. If you look at the logs you will see that the test's stopTest has returned, THEN the batch job routines are called.
This is too late for the test to assert that these batch operations did what they were supposed to do.
I think the below link might help you provide you more insight.
>> http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_scheduler.htm
Regards
Pramod
So in your example if you did some modification of accounts in your scheduled class then after your Test.stopTest you would do a SOQL query to fetch the account data back down and then do the System.assert to determine that the data changed as expected.
I opened a case to Salesforce Support asking about this. The support person tested it and discussed with the dev team. It is working as designed, but he agreed that it would be better if all the asynch processed thar would be run as a result of the code after startTest() actually were completed by the time stopTest() returned. He was going to request that this functionality be implemented in a future release.