I wrote a test class for a Batch Apex Class that has a chain of another class in the Finish method. I tried the following approach, but it still does not cover the lines in the Finish method. Is there a way for me to change the test class in order to get 100% coverage?

Here is my Batch Apex Class:

 @isTest(SeeAllData = false)
    private class BM_StageToLive_TargetPackedProd_Test{
    private static void TestStageToLive_TargetPackedProd(){
        BM_FC_Mgmt__c[] fcs = BM_StageToLive_TestDataFactory.createFCWithCrews(1, 5);

        List<BM_PPackingProductivity_Staging__c> ppsListToInsert = new List<BM_PPackingProductivity_Staging__c>();
        for (BM_FC_Mgmt__c fc : fcs){
            BM_PPackingProductivity_Staging__c newPPS = new BM_PPackingProductivity_Staging__c();
            newPPS.BM_PPS_FC__c = fc.Id;
            newPPS.BM_PPS_Date__c = Date.newInstance(2023, 01, 01);
            newPPS.BM_PPS__c = 150.1;

        insert ppsListToInsert;

        //test the class with the available data

        Date startDate = Date.newInstance(2023, 01, 01);
        Date endDate = Date.newInstance(2023, 01, 01);

        BM_StageToLive_TargetPackedProd_Batch newBatch = new 

        newBatch.startDate = startDate;
        newBatch.endDate = endDate;

        Database.queryLocator ql = newBatch.start(null);
        newBatch.execute(null, ppsListToInsert);

        // newBatch.startDate = startDate;
        // newBatch.endDate = endDate;
        // Database.executeBatch(newBatch, 1);

Here is my Test Class for the Finish Method:

 global void finish(Database.BatchableContext dbc){
    if (!Test.isRunningTest()){
        BM_StageToLive_EstimatedStock_Batch obj3 = new BM_StageToLive_EstimatedStock_Batch();
        obj3.startDate = startDate;
        obj3.endDate = endDate;
        Database.executeBatch(obj3, 30);

Thank you in advance !

  • If the second code snippet is the actual finish method to be tested, the problem is that everything it does is in an if condition that is false when running a test. Do you know why it doesn't run in a test? Can you just remove the if condition?
    – Phil W
    Apr 18, 2022 at 7:27
  • When I removed the isRunningTest() method, I received the following error: "No more than one executeBatch can be called from within a testmethod.". This led me to isolate it so that it will only run during the actual execution. Now I got it..! Seems like keeping at 86% coverage is fine. Apr 18, 2022 at 7:59
  • I guess the issue is how you are testing the batchable in general, and I am assuming you do this in code that includes Database.executeBatch rather than simply using the approach you illustrate for testing finish (which is direct invocation of the method(s) in question).
    – Phil W
    Apr 18, 2022 at 8:15

2 Answers 2


When you have a batch finish() launch a second batch via executeBatch(), you must use two testmethods:

Testmethod 1 - tests the first batch start-execute-finish sequence

Testmethod 2 - tests the second batch start - execute - finish sequence as if it had been launched by the first batch's finish().

SFDC won't actually execute a batch in a testmethod until the Test.stoptest() is reached and you won't be able to assert the results of batch 2.

I figured there is not set way of testing this other than checking if (Test.isRunningTest()) at the start of the finish function. If test is running, do nothing else execute the next batch


I ran up against the same problem, using the finish method to chain to a new execution of the batch, but finding that the tests don't run the finish method. For myself I solved it by adding the chained batch method into the Test.startTest() - Test.stopTest(), like this:

    pushMailListsToCampaignsBATCH PMLTCB = new pushMailListsToCampaignsBATCH('SELECT Id,Mailing_Lists__c FROM Contact WHERE Mailing_Lists__c<>\'\'');
    pushMailListsToCampaignsBATCH PMLTCB2 = new pushMailListsToCampaignsBATCH('SELECT Id,Mailing_Lists__c FROM Lead WHERE Mailing_Lists__c<>\'\'');

I am using a batch with a constructor which takes the querystring from the method which calls it.

global class pushMailListsToCampaignsBATCH implements Database.Batchable<sObject>{

    private String Query;
    private String QueryString;

    public pushMailListsToCampaignsBATCH(String Query){
         QueryString = Query;

    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator(QueryString);

    global void execute(Database.BatchableContext BC, List<SObject> scope) {
        // process each batch of records default size is 200

        global void finish(Database.BatchableContext BC) {
            if (query=='SELECT Id,Mailing_Lists__c FROM Contact WHERE Mailing_Lists__c<>\'\'') {
            pushMailListsToCampaignsBatch b = new pushMailListsToCampaignsBATCH('SELECT Id,Mailing_Lists__c FROM Lead WHERE Mailing_Lists__c<>\'\'');

When I found that my test would not run the finish method, I just inserted the chain call into the Test.startTEst() - Test.stopTest() block.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .