function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
JParolinJParolin 

Help with Test Class: No more than one executeBatch can be called

Hello Dev Community,

 

I have a batch test class that is giving me some trouble. It is giving me the following error when I try and deploy the class:

 

Test failure, method: BatchUpdateContactPayments.testUpdateContactPayments -- Sy
stem.UnexpectedException: No more than one executeBatch can be called from withi
n a testmethod. Please make sure the iterable returned from your start method m
atches the batch size, resulting in one executeBatch invocation. stack External
entry point

 

Here is the test method I'm trying to deploy the class with:

 

public static testMethod void testUpdateContactPayments() {

Account[] accts = new Account[]{};
for (integer i=0;i<11;i++) {
accts.add(new Account(name='DAcct1a' + i, pymt_Payments_Made__c = 10));	
}
for (integer i=0;i<11;i++) {
accts.add(new Account(name='DAcct1b' + i));	
}
insert accts;

Account acct1 = new Account(name='DAcct1', pymt_Payments_Made__c = 10);
insert acct1;

Contact[] contacts = new Contact[]{};
//contacts with account and no total payment amount not changed
for (integer i=0;i<5;i++) {
contacts.add(new Contact (firstname = 'Joey',
lastname = 'ApexTest'+ i,
mailingstreet = '123 Oak',
mailingcity = 'Encinitas',
mailingpostalcode = '111111',
mailingcountry = 'US',
email = 'joeyapextest12354@test.com',
pymt_Payments_Made__c = 10,
accountid = acct1.id));
}
//contacts with account and total payment amount changed
for (integer i=0;i<5;i++) {
contacts.add(new Contact (firstname = 'Joey',
lastname = 'ApexTest'+ i,
mailingstreet = '123 Oak',
mailingcity = 'Encinitas',
mailingpostalcode = '111111',
mailingcountry = 'US',
pymt_Payments_Made__c = 0,
email = 'joeyapextest12354@test.com',
accountid = acct1.id));
}
//contacts with no account
for (integer i=0;i<11;i++) {
contacts.add(new Contact (firstname = 'Joey',
lastname = 'ApexTest'+ i,
mailingstreet = '123 Oak',
mailingcity = 'Encinitas',
mailingpostalcode = '111111',
mailingcountry = 'US',
email = 'joeyapextest12354@test.com'));
}
insert contacts;

String query = '';
    if (contacts.size()>0){
        String contactIdList = '';
        for (Contact c :contacts) {
            contactIdList += '\''+c.Id+'\',';
        }
        contactIdList = '('+contactIdList+')';
        contactIdList = contactIdList.replace(',)',')');  // remove trailing comma
        query  = 'Select id, pymt__Account__r.pymt_Payments_Made__c, pymt__Contact__r.pymt_Payments_Made__c, pymt__Contact__r.Account.pymt_Payments_Made__c, pymt__Account__c, pymt__Contact__c, pymt__Contact__r.AccountId, pymt__amount__c, pymt__status__c from pymt__PaymentX__c where (pymt__status__c like \'Completed\'  or pymt__Status__c like \'Charged\') and isDeleted = false and pymt__Amount__c <> null and (pymt__Account__r.Name like \'DAcct1%\' or pymt__contact__c in '+contactIdList+') limit 200';  

}
    

List<pymt__PaymentX__c> payments = new List<pymt__PaymentX__c>{};
List<pymt__PaymentX__c> LoneAcctpayments = new List<pymt__PaymentX__c>{};
for (Account a :accts) {
    for (Integer i=0; i<2; i++) {
    	
    LoneAcctpayments.add(new pymt__PaymentX__c(name = 'ApexTest Payment1: '+ a.name,
    pymt__status__c = 'Completed',
    pymt__amount__c = 20.00,
    pymt__account__c = a.id));
    }
	
}
insert LoneAcctpayments;

for (Contact c :contacts) {
        
    for (Integer i=0; i<2; i++) {
    payments.add(new pymt__PaymentX__c(name = i+ 'ApexTest Payment1: '+ c.lastname,
    pymt__status__c = 'Completed',
    pymt__amount__c = 5.00,
    pymt__contact__c = c.id));
    }
}


pymt__PaymentX__c payment2 = new pymt__PaymentX__c();
payment2.name = 'ApexTest Payment2: '+ acct1.name;
payment2.pymt__status__c = 'Completed';
payment2.pymt__amount__c = 5.00;
payment2.pymt__account__c = acct1.id;
payments.add(payment2);
insert payments;


Test.StartTest();
BatchUpdateContactPayments batchUpdate = new BatchUpdateContactPayments(query);
//apexTestMode = true; 
ID batchprocessid = Database.executeBatch(batchUpdate);
Test.StopTest();
//Contact cont = [Select id, pymt_payments_made__c from Contact where Id = :contacts[0].Id];
//System.debug('APEXDEBUG' + cont.pymt_payments_made__c);
//Account acc = [Select id, pymt_payments_made__c from Account where Id =: acct1.id];
//System.debug('APEXDEBUG' + acc.pymt_payments_made__c);


}

 

I've browsed the forums and haven't found an answer that I've been able to apply. I'm looking for any pointers or help to understand what I can do to fix this error. Any help is much appreciated.  Thanks all!

 

 

 

 

Starz26Starz26

In you batch class

 

add a variable

 

boolean isTest = False;

 

In you start statement add a line to modify the query string:

 

if(isTest)

  query += ' Limit 200';

 

in your test method

 

set

 

batchUpdate.isTest = true;

 

 

you cannot have more than one run of the batch in a test method and setting the batch size to 200 does not work you have to limit the number of records to 200...

 

If anyone has a better solution please do share.

JParolinJParolin

Hmmm, I don't where I could do this elsewhere in my batch script. Here is the full script:

 

Any further assistance would be greatly helpful. Really in a bind.

 

global class BatchUpdateContactPayments implements Database.Batchable<sObject>, Database.Stateful {


  global final String query;
   global Map<String,Decimal> cont_totals;
   global Map<String,Decimal> acct_totals;
   global List<Map<String,totals>> allContactMaps;
   global List<Map<String,totals>> allAccountMaps;

   private class totals {
   	public Decimal origTotal = 0.0;
   	public Decimal newTotal = 0.0;
   }
   
   //global Map<String,Integer> count;
   global static Boolean apexTestMode = false;  
   global BatchUpdateContactPayments(String q){
    
    cont_totals = new Map<String, Decimal>{};
    acct_totals = new Map<String, Decimal>{};
    this.query = q;
    allContactMaps = new List<Map<String,totals>>();
    allContactMaps.add(new Map<String,totals>());
    allAccountMaps = new List<Map<String,totals>>();
    allAccountMaps.add(new Map<String,totals>());
    
   }


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

private Map<String,totals> getCurrentContactMap(pymt__PaymentX__c p) {

for(Map<String,totals> currentMap : this.allContactMaps) {
		if (currentMap.containsKey(p.pymt__Contact__c)) { 
			return currentMap;
	}	
 }
 
	totals t = new totals();
	if (p.pymt__Contact__r.pymt_Payments_Made__c != null) {
		t.origTotal = p.pymt__Contact__r.pymt_Payments_Made__c;
	}
	

	if(this.allContactMaps[allContactMaps.size() - 1].size() == 999) {		
		Map<String,totals> newMap = new Map<String,totals>();		
		newMap.put(p.pymt__Contact__c, t);
		this.allContactMaps.add(newMap);
		return newMap;
	}
	else {
		Map<String,totals> currentMap =	this.allContactMaps[allContactMaps.size() - 1];
		currentMap.put(p.pymt__Contact__c, t);
		return currentMap;
	}
	
			 
}

private Map<String,totals> getCurrentAccountMap(pymt__PaymentX__c p, boolean isContactAcct) {
String AcctID;
Decimal TotalPymtsMade;

if (isContactAcct) {
	AcctID = p.pymt__Contact__r.AccountId;
	TotalPymtsMade = p.pymt__Contact__r.pymt_Payments_Made__c;
}
else {

	AcctID = p.pymt__Account__c;
	TotalPymtsMade = p.pymt__Account__r.pymt_Payments_Made__c;

}

for(Map<String,totals> currentMap : this.allAccountMaps) {
		if (currentMap.containsKey(AcctID)) { 
			return currentMap;
	}	
 }
 
	totals t = new totals();
	if (TotalPymtsMade != null) {
		t.origTotal = TotalPymtsMade;
	}
	

	if(this.allAccountMaps[allAccountMaps.size() - 1].size() == 999) {		
		Map<String,totals> newMap = new Map<String,totals>();		
		newMap.put(AcctID, t);
		this.allAccountMaps.add(newMap);
		return newMap;
	}
	else {
		Map<String,totals> currentMap =	this.allAccountMaps[allAccountMaps.size() - 1];
		currentMap.put(AcctID, t);
		return currentMap;
	}
	
			 
}


global void execute(Database.BatchableContext BC, List<Sobject> scope){
   	Decimal value;
	Map<String,totals> ContactMap;
	Map<String,totals> AccountMap;
      for(Sobject obj : scope) {
        pymt__PaymentX__c p = (pymt__PaymentX__c)obj;

    	if ((p.pymt__Contact__c == null) && (p.pymt__Account__c != null)) {
    		AccountMap = getCurrentAccountMap(p, false);
    		AccountMap.get(p.pymt__Account__c).newTotal +=p.pymt__Amount__c;
		}
	
            if (p.pymt__Contact__c != null) {				
				ContactMap = getCurrentContactMap(p);
				ContactMap.get(p.pymt__Contact__c).newTotal +=p.pymt__Amount__c;
        			if (p.pymt__Account__c != null) {
        				AccountMap = getCurrentAccountMap(p, false);
        				AccountMap.get(p.pymt__Account__c).newTotal +=p.pymt__Amount__c;        				
        			}
        			if(p.pymt__Account__c == null && p.pymt__Contact__r.AccountId != null) {
        				AccountMap = getCurrentAccountMap(p, true);
        				AccountMap.get(p.pymt__Contact__r.AccountId).newTotal +=p.pymt__Amount__c;        				
	        		}
        	}

      }      
   }



global void finish(Database.BatchableContext BC){    
List<Contact> contacts = new List<Contact>{};
List<Account> accts = new List<Account>{};
   	
for(Map<String,totals> cm : this.allContactMaps) {
		if (cm.size() > 0) {
     		for (String Contkey :cm.keySet()) {
     			Totals t = cm.get(ContKey);    			
     			
     			if (t.newTotal != t.origTotal && contacts.size() < 1000) {     				
     				contacts.add(new Contact(id=Contkey, pymt_Payments_Made__c = t.newTotal));
     			}     
    		}	
		}	
	
}

for(Map<String,totals> am : this.allAccountMaps) {
	if (am.size() > 0) {
		for (String Acctkey :am.keyset()) {
			Totals t = am.get(Acctkey);
			if (t.newTotal != t.origTotal && contacts.size() < 1000) {		
     			accts.add(new Account(id=Acctkey, pymt_Payments_Made__c = t.newTotal));
			}
     	}
	}
}     

if (contacts.size() > 0) {
     try {
     update contacts;
     } catch (Exception ex) {
     System.debug('Error updating payments_made__c total on contacts. '+ex);
     }
}


if (accts.size() > 0) {
     try {
     update accts;
     } catch (Exception ex) {
     System.debug('Error updating payments_made__c total on accounts. '+ex);
     }
 }



   }
   
public static testMethod void testUpdateContactPayments() {

Account[] accts = new Account[]{};
for (integer i=0;i<11;i++) {
accts.add(new Account(name='DAcct1a' + i, pymt_Payments_Made__c = 10));	
}
for (integer i=0;i<11;i++) {
accts.add(new Account(name='DAcct1b' + i));	
}
insert accts;

Account acct1 = new Account(name='DAcct1', pymt_Payments_Made__c = 10);
insert acct1;

Contact[] contacts = new Contact[]{};
//contacts with account and no total payment amount not changed
for (integer i=0;i<5;i++) {
contacts.add(new Contact (firstname = 'Joey',
lastname = 'ApexTest'+ i,
mailingstreet = '123 Oak',
mailingcity = 'Encinitas',
mailingpostalcode = '111111',
mailingcountry = 'US',
email = 'joeyapextest12354@test.com',
pymt_Payments_Made__c = 10,
accountid = acct1.id));
}
//contacts with account and total payment amount changed
for (integer i=0;i<5;i++) {
contacts.add(new Contact (firstname = 'Joey',
lastname = 'ApexTest'+ i,
mailingstreet = '123 Oak',
mailingcity = 'Encinitas',
mailingpostalcode = '111111',
mailingcountry = 'US',
pymt_Payments_Made__c = 0,
email = 'joeyapextest12354@test.com',
accountid = acct1.id));
}
//contacts with no account
for (integer i=0;i<11;i++) {
contacts.add(new Contact (firstname = 'Joey',
lastname = 'ApexTest'+ i,
mailingstreet = '123 Oak',
mailingcity = 'Encinitas',
mailingpostalcode = '111111',
mailingcountry = 'US',
email = 'joeyapextest12354@test.com'));
}
insert contacts;

String query = '';
    if (contacts.size()>0){
        String contactIdList = '';
        for (Contact c :contacts) {
            contactIdList += '\''+c.Id+'\',';
        }
        contactIdList = '('+contactIdList+')';
        contactIdList = contactIdList.replace(',)',')');  // remove trailing comma
        query  = 'Select id, pymt__Account__r.pymt_Payments_Made__c, pymt__Contact__r.pymt_Payments_Made__c, pymt__Contact__r.Account.pymt_Payments_Made__c, pymt__Account__c, pymt__Contact__c, pymt__Contact__r.AccountId, pymt__amount__c, pymt__status__c from pymt__PaymentX__c where (pymt__status__c like \'Completed\'  or pymt__Status__c like \'Charged\') and isDeleted = false and pymt__Amount__c <> null and (pymt__Account__r.Name like \'DAcct1%\' or pymt__contact__c in '+contactIdList+') limit 200';  

}
    

List<pymt__PaymentX__c> payments = new List<pymt__PaymentX__c>{};
List<pymt__PaymentX__c> LoneAcctpayments = new List<pymt__PaymentX__c>{};
for (Account a :accts) {
    for (Integer i=0; i<2; i++) {
    	
    LoneAcctpayments.add(new pymt__PaymentX__c(name = 'ApexTest Payment1: '+ a.name,
    pymt__status__c = 'Completed',
    pymt__amount__c = 20.00,
    pymt__account__c = a.id));
    }
	
}
insert LoneAcctpayments;

for (Contact c :contacts) {
        
    for (Integer i=0; i<2; i++) {
    payments.add(new pymt__PaymentX__c(name = i+ 'ApexTest Payment1: '+ c.lastname,
    pymt__status__c = 'Completed',
    pymt__amount__c = 5.00,
    pymt__contact__c = c.id));
    }
}


pymt__PaymentX__c payment2 = new pymt__PaymentX__c();
payment2.name = 'ApexTest Payment2: '+ acct1.name;
payment2.pymt__status__c = 'Completed';
payment2.pymt__amount__c = 5.00;
payment2.pymt__account__c = acct1.id;
payments.add(payment2);
insert payments;


Test.StartTest();
BatchUpdateContactPayments batchUpdate = new BatchUpdateContactPayments(query);
//apexTestMode = true; 
ID batchprocessid = Database.executeBatch(batchUpdate);
Test.StopTest();
//Contact cont = [Select id, pymt_payments_made__c from Contact where Id = :contacts[0].Id];
//System.debug('APEXDEBUG' + cont.pymt_payments_made__c);
//Account acc = [Select id, pymt_payments_made__c from Account where Id =: acct1.id];
//System.debug('APEXDEBUG' + acc.pymt_payments_made__c);

}

}

 

Starz26Starz26

Hmm.....

 

not sure, it looks like you are already using Limit 200 in your query string....

 

odd

dmchengdmcheng

What does Limits.getLimitQueryLocatorRows() tell you?  Are you under 200 records?

UVUV

I have got the same issue few days back in my Sandbox wherein as a fix I limited the query by 1. I dont know why I was getting this issue as my batch size was 200 and I was limiting the query by 200 in my test class.