2

I have written my first Apex batch processing class. It works when I manually create records and run it in my sandbox. It is very simple. We've added a set of fields that can have up to 3 values: 'Unknown', 'Yes', 'No'.

The current batch simply overwrites the value in each of the new fields with 'Unknown'. Eventually, it will employ logic based on other field values to assign a correct value to each field being assigned to. (This information was inconsistently collected, and we're trying to consolidate it so that it is all represented in a consistent way.)

When I create Account records manually and run the batch, everything goes as expected. When I run the test code, with a constant that says create 1 and only 1 test Account record, it passes. With any number of test Account records greater than 1 that I've tried, it fails with this message:

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

It seems that should be easy to fix. However, as I understand it, the batch size is 200. Two test records should not exceed that. So it seems there is something I don't understand about what I'm doing or what that exception means. I have tried "200". I'm hoping someone can say - "Don't do it that way!" and show me a way that will work.

Here is the test code, which works when generating 1 and not for 2 or more test Account records. We don't use the Fax field in practice, so the code populates that so that when we test in production, the code will only pull the records generated in setup(). Furthermore, in the test class, if I comment out all the code, and leave only an empty test and empty verification that returns True, I still get the same failure. So the failure appears to be occurring in the setup() method. I.e. even if I don't invoke batch processing, I get the error.

Here is the test code, which works with a limit of 1 Account, and fails with larger numbers:

@isTest
public class FillMemberYearUnknown_test 
{

    @testSetup
    static void setup() {
        List<Account> lstAccount= new List<Account>();
        String value = 'Yes';

        for(Integer i=0 ;i <2;i++)
        {
            Account acc = new Account();
            acc.Name ='Account_User_'+i;
            acc.Member2010_Acct__c = value;
            acc.Member2011_Acct__c = value;
            acc.Member2012_Acct__c = value;
            acc.Member2013_Acct__c = value;
            acc.Member2014_Acct__c = value;
            acc.Member2015_Acct__c = value;
            acc.Member2016_Acct__c = value;
            acc.Member2017_Acct__c = value;
            acc.Member2018_Acct__c = value;
            acc.Member2019_Acct__c = value;
            acc.Member2020_Acct__c = value;
            acc.Member2021_Acct__c = value;
            acc.Member2022_Acct__c = value;
            acc.Fax = '555-555-5555';

            lstAccount.add(acc);
        }

        insert lstAccount;
    }

    static testmethod void test() {

        Test.startTest();

            FillMemberYearUnknown obj = new FillMemberYearUnknown();
            DataBase.executeBatch(obj);

        Test.stopTest();
        System.assert(verifyResults());

    }

    static boolean verifyResults() {

        String value = 'Unknown';
        boolean results = False;
        List<Account> accts = [SELECT Id,Name,Fax, Member2010_Acct__c,Member2011_Acct__c,Member2012_Acct__c,Member2013_Acct__c,Member2014_Acct__c,Member2015_Acct__c,Member2016_Acct__c,Member2017_Acct__c,Member2018_Acct__c,Member2019_Acct__c,Member2020_Acct__c,Member2021_Acct__c,Member2022_Acct__c FROM Account where Fax = '555-555-5555' LIMIT 50];

        for(Account acc : accts) {
            results = True;
            if (acc.Fax == '555-555-5555' && (acc.Member2010_Acct__c != value ||
                acc.Member2011_Acct__c != value ||
                acc.Member2012_Acct__c != value ||
                acc.Member2013_Acct__c != value ||
                acc.Member2014_Acct__c != value ||
                acc.Member2015_Acct__c != value ||
                acc.Member2016_Acct__c != value ||
                acc.Member2017_Acct__c != value ||
                acc.Member2018_Acct__c != value ||
                acc.Member2019_Acct__c != value ||
                acc.Member2020_Acct__c != value ||
                acc.Member2021_Acct__c != value ||
                acc.Member2022_Acct__c != value) ) {
                   return (False); 
                }
        }
        return (results);
    }
}

Here is the batch processing class under test:

global class FillMemberYearUnknown implements Database.Batchable<sObject> {
        global Database.QueryLocator start(Database.BatchableContext BC) {
                String query = 'SELECT Id,Name,Member2010_Acct__c,Member2011_Acct__c,Member2012_Acct__c,Member2013_Acct__c,Member2014_Acct__c,Member2015_Acct__c,Member2016_Acct__c,Member2017_Acct__c,Member2018_Acct__c,Member2019_Acct__c,Member2020_Acct__c,Member2021_Acct__c,Member2022_Acct__c FROM Account';
                return Database.getQueryLocator(query);
        }

        global void execute(Database.BatchableContext BC, List<Account> scope) {
                String value;
                value = 'Unknown';
                for(Account a : scope) {
                    a.Member2010_Acct__c = value;
                    a.Member2011_Acct__c = value;
                    a.Member2012_Acct__c = value;
                    a.Member2013_Acct__c = value;
                    a.Member2014_Acct__c = value;
                    a.Member2015_Acct__c = value;
                    a.Member2016_Acct__c = value;
                    a.Member2017_Acct__c = value;
                    a.Member2018_Acct__c = value;
                    a.Member2019_Acct__c = value;
                    a.Member2020_Acct__c = value;
                    a.Member2021_Acct__c = value;
                    a.Member2022_Acct__c = value;
                }
                update scope;
        }

        global void finish(Database.BatchableContext BC) {
        }
}

I'd sure appreciate any insight that you might be able to offer. I realize there may be a better way to achieve the end goal with the fields, but along the way, I'd really like to understand why this test of batch processing is failing.

  • Clarification - The sandbox I'm working in when I run the test code has no Account records in it before the test runs and no account records in it after the test runs. – Rob Mackie Aug 20 at 19:23
  • 2
    Check your trigger on account, if you are calling database.execute batch again? Something like if its 1 record process, if more than 1 , just execute some batch, i stumbled upon something similar few months back – Pranay Jaiswal Aug 20 at 19:43
  • I also think that you initialize some other process while inserting your Accounts as you say it occurs within setup, thus the batch has not even executed. Maybe also google helps, I just found a lot of questions/anwers on the error, including this description from Salesforce: help.salesforce.com/… Maybe you can misuse Test.isRunningTest for further debugging... – user40501 Aug 21 at 12:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.