18

I just used the new feature that allows me to call a SecondBatchable class from the finish() method of the FirstBatchable class.

global with sharing class FirstBatchable implements Database.Batchable<SObject>, Database.Stateful {

   global void finish(Database.BatchableContext context) {

      SecondBatchable batch = new SecondBatchable();
      Database.executeBatch(batch, 5); // It even fails with value 1
   }
   ...
}

This all works like a charm. But... All my tests of this class

@isTest
private static void testBatch() {
    ...
    Test.startTest();

    FirstBatchable batch = new FirstBatchable();
    Database.executeBatch(batch, 200); // It even fails with value 1

    Test.stopTest();

    ...
} 

fail with the error:

System.UnexpectedException: No more than one executeBatch can be called from within a testmethod. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.

I guess the problem is as we chain TWO batches the Test.startTest and Test.stopTest bring the batchSize down to 1 but 1 + 1 != 1.

Any suggestions?!

4

I've encountered this issue when testing a scheduled class that launches a batch job. When the code hits Test.startTest() any queued jobs get called which in turns queued a batch job. What starting happening is that at the termination of the test method there was a second clear out of the queued jobs which caused a multi-batch execution issue.

In your case I'm guessing that your finish method gets run when you hit Test.startTest() but you don't get an exception until your test method concludes and the second purge happens.

To work around this I aborted the queued second job as a last statement in the test. For example:

@isTest
private static void testBatch() {
    ...
    Test.startTest();
    FirstBatchable batch = new FirstBatchable();
    Database.executeBatch(batch, 200);
    Test.stopTest(); // your batch executes here

    // abort the pending batch job
    AsyncApexJob pending = [select id from AsyncApexJob where apexClass.Name = 'SecondBatchable'];
    system.abortJob(pending.id);
} 

If that doesn't work you'll want to just through a test switch in there. From a testing perspective you should be able to break up the tests into segments that test each batch individually. You'll just need to do the work of the first batch in the test setup when testing the second.

7

You can test this scenario. You have to make sure, that for both batches just 1 execution is needed by keeping the batch size the highest possible. Sometimes you needed to distinguish between the test case and the real life scenario exactly for this reason.

SecondBatchable batch = new SecondBatchable();
Integer batchSize = Test.isRunningTest() ? 500 : 5
Database.executeBatch(batch, batchSize);
  • 1
    Sounds good ;) I'll give it a try. – Robert Sösemann Mar 29 '13 at 15:34
  • 1
    This doesn't really work when you call the second Batch from the finish() method of the first Batch. – Robert Sösemann Jul 29 '13 at 14:44
6

I hit the same problem and ended up adding a test.IsRunningTest() check for the second batch and just testing the second batch separately...not ideal, but I don't see another way..?

  • Had similar experience. Only one batch will run in a test. – Acuariano Mar 27 '13 at 18:27

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.