You need to sign in to do that
Don't have an account?
test methods for Batch Apex is not causing execute() method to run
I have a very simple Batch class and I am trying to write a unit test to cover it but the execute method in this batch class is never executing. I'm stumped.
Batch Class:
global class ideaCleanBatch implements Database.Batchable<sObject>{
global Database.QueryLocator start(Database.BatchableContext bc){
//We want to process all Ideas
return Database.getQueryLocator('select Id from Idea');
}
global void execute(Database.BatchableContext bc, List<sObject> objects){
Set<Id> ideaIds = new Set<Id>();
for(sObject s : objects){
Idea i = (Idea)s;
ideaIds.add(i.Id);
}
//Send ideas to ideaClean for processing
ideaClean.recalcNumbers(ideaIds);
}
global void finish(Database.BatchableContext bc){
system.debug('All done.');
}
}
Test Method:
static testMethod void ideaBatchTest(){
List<Idea> ideas = new List<Idea>();
Id communityId = [select Id from Community limit 1].Id;
for(Integer i = 0; i < 200; i++){
ideas.add(new Idea(Title = 'myIdea' + i, CommunityId = communityId));
}
insert ideas;
Test.startTest();
ideaCleanBatch job = new ideaCleanBatch();
ID batchprocessid = Database.executeBatch(job);
Test.stopTest();
}
Coverage:
Thanks,
Jason
We have the exact same problem. Hopefully there will be a fix soon!
Commenting out assert statements in a test method is not a best practice :). But it's what we're forced to do now because of this issue.
I finally got an answer...
Apparently the test context for batch apex only allows for 200 records. Anything over that limit will not execute, at all.
One typical way of limiting the number of records is to have a string as a member variable that stores the query. The test method then puts a limit on the query of 200 records. For example, the following code achieves 100% coverage:
global class BatchClass implements Database.Batchable<sObject>{
public String query = 'select id from account';
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<sObject> scope){
for (Account a : (List<Account>)scope){
System.debug(a);
}
}
global void finish(Database.BatchableContext BC){
System.debug('finished');
}
}
@isTest
private class TestBatchClass{
static testMethod void testBatchClass() {
BatchClass bc = new BatchClass();
bc.query = 'Select Id From Account Limit 200';
Test.startTest();
Database.executeBatch(bc, 200);
Test.stopTest();
}
}
I think this is sort of lame as I feel like the code should just know this is a test and only return 200 records so one batch is executed.
This is what the docs say:
The testing framework allows developers to test one execution of the executeBatch method.To guarantee your test runs within the governor limits, add LIMIT 200 to the query.
I easily misinterpreted this as it will only exexcute one batch regardless of the amount returned and the limit 200 is just to make the code more optimized and was not required.
-Jason
Reference to docs: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_batch_interface.htm
under testing batch apex...
I agree with you that this is easy to miss:
"To guarantee your test runs within the governor limits, add LIMIT 200
to the query"
Larry
Although, in defense of the doc writers, it is easier to understand when looking at the comments in the sample code:
It's probably so that in the context of a test, they can ensure that the batch method will execute immediately and completely, allowing the test method to complete and execute System.asserts on the results.
If the batch had to reschedule to complete it's work, salesforce would have to figure out how to remove the delay between runs and force the subsequent jobs to run immediately.
Ron
I've tried the suggestions in this thread, and I still can't get the execute to test. Now, I'm having to work with someone else's code unfortunately and I have the impression it wasn't written correctly.
For example the query was actually built inside the start method, rather than outside the method as a class variable - this prevented any ability for me to use the LIMIT 200 in the test query.
I've now added the query as a class string variable, and am updating the query to include LIMIT 200 in the test before it enters the start method.
Also, the debug logs show the query is returning the test records I created. I'll try to simplify the code:
Here's the test method:
Again, the query is returning records inserted by the testmethod, and the start method is working. The test however never runs the execute method.
So, given that the 200 record limit is being imposed on the batch query in the test, the query is returning records, and thre are no other errors in the debug log, what am I doing or not doing?
The job is more complex than this as far as the internal code for the execute and finish methods, but since neither of them are being called, this isn't impacting the result. However, if it will help I'll add the rest. Otherwise, the process seems to be working in practice, but I can't improve the test results until I can get the rest of the methods to run.
OldDeadBug, were you able to solve the problem?
I'm stuck in the same place as you.
I just insert 8 leads in a testmethod for the bacthable class to process but the execute method does not execute nor leave any trace in the debug log.
Any clue on this?
Thanks
Has this anything to do with the type of sandbox I'm using?
I does not work on a Developer sandbox but it works find on a Config Only sandbox.
Nothing yet. The only 'solution' provided is to ensure your test batch is limited to 200 records. I've done that in my query, as displayed above. The start method runs just fine, but the execute doesn't run at all, and there is no indication of what the error is.
I thought the whole idea of this process is that all three methods get called if there aren't any obvious errors. But currently the test process isn't set up to effectively test batch jobs, or at least to return some kind of error message when the test doesn't complete.
I guess the Salesforce people assume that if the execute method doesn't run in the test that its a batch size problem. I don't think that is the problem in my case. Its probably something simple but so far no one has pointed it out.
I added this Batchclass and its test method to see if this actually worked. This has been flagged as a solution, but after running the test I get the same problem:
The start method runs, the SOQL query returns a result under 200 records, the execute method is bypassed altogether, and then the finish method runs.
The 200 record limit on the test is necessary, but this is not the reason for the batch execute method not running.
The Test class now supports the method Test.isRunningTest() which you can use to determine whether or not you are in apex test mode ... and insert your "LIMIT 200" clause into the SOQL.
- Ron
Appreciate the response, but I'm not clear on where to use the test.isRunningTest() method in this case.
At which point in the batch class do I need to inform it that a test is running??
Also, I'm updating the SOQL query to insert the 'LIMIT 200' in the test method before running the execution.
Since the execute method is the only one not firing, are you suggesting I add the isRunningtest method before the execute method, such as in the start method??
Not sure what you're suggesting here, nor how it will impact the problem of the execute piece of the batch process not running. Any help is appreciated by myself and others.
As far as testing a batch process is concerned I believe I've found the best workaround to get the batch class to test successfully.
Since even a very simple batch class and test such as that provided earlier in this thread by TehNerd doesn't run the 'execute' method, regardless of whether the LIMIT 200 is added to the QueryLocator query, I chose to add a separate method to the batch class called 'execbatch()' which is referenced from the 'execute' method. Basically it looks like this:
.. this will run the standard batch methods start, execute, and finish - but since the execute method doesn't run during the test, this will be missed. So although you won't get 100%, the additional execbatch() method will get coverage of what should be the execute method logic.
If anyone can provide a working batch class and test method that can demonstrably test the execute method, I really want to see it. I've been unable to test the execute on even the simplest of batch classes. It might be a really simple error I'm making but I've so far been unable to find it. This workaround will get your code tested while keeping the batch processing intact.
That's a good approach.
As another alternative, you can assign an alternate SOQL string to a public member variable on the batch class before running it - essentially changing the default query to one that is more restrictive and produces the smaller result set that you need for the tests.
Cheers,
Ron
I think something has changed recently affecting batch apex. I ran tests at the start of March and got 99% coverage but ran today and got 23% as it wasn't running the execute method. Tried to use the limit 200 technique but this didn't do a thing. Had to call the execute method seperately from everything else:
Same problem here, glad it's not just me,
Just wrote a new batch class and copied the test code from another batch test I'd written months previous, which I know for sure got me 100% coverage (in fact, I'd even wrote in comments that it got me 100%!). Now the start and finish methods are run, but execute isn't even called.
Regards
Steven
bah, any resolution to this issue? My execute method is being bypassed.
Do some debugging to make sure your query is actually returning results, if it doesnt return results your execute method wont be called at all. Limit the query to 200 results too.
Spot-on. My class was querying another table that happened to be empty in the sandbox. Lesson learned: no data = no execute
I also decided to pull the query statement out of the batch class so I could dynamically create it. Here is how I called it from my schedulable class
and here is how I ran it from my test class to include the limit of 200
I am a firm believer that this is a serious bug...
I have an org where I have two test methods in separate classes that call the same batch, same query, and same query results. One works and calls the execute, the other fails. This is a major problem as we are heavy batch users.
I have desparately tried to figure out what I need to do to trick the system into running the entire batch. Nothing.
As a final test, I deployed the code to another dev org with the same config. In that org, the batch works on both of the above methods.
Seems that this is happening only in test environment. I tried this in development env and it worked perfectly fine. But when I copied the code to test, it bypassed the execute method.
This thread gave me an epiphany sort of moment with the same if not similar issue I was having.
I was returning an empty iterable<sObject> in my start method. The brunt of the logic is in the execute method, since I have to query across multiple objects. The code worked fine when called via a Tab / custom visualforce page (Requirement to manually kick off the batch process).
During unit testing, as everyone else as mentioned, the execute method was not firing.
So in the start method, I just added a dummy sObject, without any SOQL or DML to fix the unit test failure.
Its now happening to me. Please help me
Happening to me as well. The execute method is being bypassed for seemingly no reason, with no trace of why in log files.
After seeing renewed activity on this thread, it occurred to me that some of the folks posting might be writing these batch scripts using the latest API (v 25). Don't forget that unless you run with @isTest(UseExistingData=true) SF will clear out all data before running the test. The query in your script might be returning 0 records when you are expecting data to be there.
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_annotation_isTest.htm
~ Ron
Use @IsTest(SeeAllData=true)Annotation on the top your test class
I was only getting 40% test coverage... but when I moved my "update" statement into the "global void finish(Database.BatchableContext BC)"... finally I got 100% test coverage.
After adding @isTest(SeeAllData=true) annotation on top of the test class everything worked fine with me.
I am facing the same issue, the execute method in test class did not run.
I tried to put limit 200 and limit 1 but the error persist. Same for adding the @isTest(SeeAllData=true) annotation on top of the test class.
The query returns value also.
Any solution other than the solutions mentioned above.
Thank you in advance.
Regards,