You need to sign in to do that
Don't have an account?
Sisodia Saurabh
Error in test class for batch apex sending emails to users
Hi,
I have written batch to send emails to users not logged in more than 20 days. it is working when I use schedular with batch limit 10.
But when I am trying to write test class I am getting below error:
"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."
--- my batch --
global class SendEmailtoNonActiveUsersBatch implements database.Batchable<sObject> {
Exception[] errors = new Exception[0];
global String query;
global Database.QueryLocator start(Database.BatchableContext bc) {
string query = 'SELECT id,Firstname,Lastname,Profile.name, email,Isactive, LastLoginDate, category__c,IsEmailSendToNonActive__c FROM User where IsActive=True and Category__c= \'Employee\' and IsEmailSendToNonActive__c != true and LastLoginDate < LAST_N_DAYS:20 order by Firstname ASC ';
return database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc, List<User> scope){
system.debug('Scope size' +scope.size());
try{
String currentUserLink = URL.getSalesforceBaseUrl().toExternalForm() + '/';
if(scope.size() >0){
for(user u: scope){
if(u.IsEmailSendToNonActive__c != true){
u.IsEmailSendToNonActive__c = true;
string[] toAddress = new string[] {u.Email};
string subject = 'Notification Of User Deactivation';
string plainBody = 'TEST'
SendEmail(toAddress,subject, plainBody, null, null );
update u;
}
}
}
}
catch(exception e){
errors.add(e);
}
}
global void finish(Database.BatchableContext bc){
//Admins email addresses
List<string> emailAdd = new List<string>();
for(AdminsEmailList__c emad : AdminsEmailList__c.getAll().values())
{
system.debug('emad.Email__c:'+emad.Email__c);
emailAdd.add(emad.Email__c);
}
List<AggregateResult> numberOfRows = [Select count(id) from user where IsEmailSendToNonActive__c=True and lastmodifieddate = today];
integer numRow = (integer)numberOfRows[0].get('expr0');
AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
FROM AsyncApexJob WHERE Id =:BC.getJobId()];
//check for errors if no error then proceed
string errorString;
for(Exception s: errors)
{
errorString = errorString + s.getMessage();
}
if(!errors.isEmpty()) {
string errSub = 'Error(s) occurred during sending emails to Non Active user batch process.';
string errBody = 'below is the error details: \n\n'+errorString;
SendEmail(emailAdd, errSub, errBody, null, null);
}
}
public void SendEmail(List<string> toEmailAdd, string subject, string body, string attchmentName, string attachment){
system.debug('toEmailAdd::'+toEmailAdd);
if(toEmailAdd != null && !toEmailAdd.isEmpty()){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(toEmailAdd);
mail.setSubject(subject);
mail.setSaveAsActivity(false);
mail.setPlainTextBody(body);
Messaging.sendEmail(new Messaging.Email[] { mail });
}
}
}
--- Schedular --
global class ScheduleSendEmailToNonActiveUsers implements Schedulable{
global void execute(SchedulableContext sc){
SendEmailtoNonActiveUsersBatch s = new SendEmailtoNonActiveUsersBatch();
database.executeBatch(s, 10);
}
}
--- TEST CLASS -----
@isTest
public class SendEmailtoNonActiveUsersBatch_Test {
@IsTest(seeAllData=true)
public static void SendEmailTest_positive()
{
User us = [Select id from User where Id = :UserInfo.getUserId()];
System.runAs(us)
{
List<user> uu = [SELECT id,Firstname,Lastname,Profile.name, email,Isactive, LastLoginDate, category__c,IsEmailSendToNonActive__c FROM User where IsActive=True and Category__c= 'Employee' and IsEmailSendToNonActive__c != true and LastLoginDate < LAST_N_DAYS:20 order by Firstname ASC Limit 10];
Test.startTest();
SendEmailtoNonActiveUsersBatch s = new SendEmailtoNonActiveUsersBatch();
database.executeBatch(s);
Test.stopTest();
}
}
}
Another observation: test class should execute DML query menstioned in test class(resulte records 10). But when I run the test class it take query mentioned in batch apex(result records 162).
I have written batch to send emails to users not logged in more than 20 days. it is working when I use schedular with batch limit 10.
But when I am trying to write test class I am getting below error:
"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."
--- my batch --
global class SendEmailtoNonActiveUsersBatch implements database.Batchable<sObject> {
Exception[] errors = new Exception[0];
global String query;
global Database.QueryLocator start(Database.BatchableContext bc) {
string query = 'SELECT id,Firstname,Lastname,Profile.name, email,Isactive, LastLoginDate, category__c,IsEmailSendToNonActive__c FROM User where IsActive=True and Category__c= \'Employee\' and IsEmailSendToNonActive__c != true and LastLoginDate < LAST_N_DAYS:20 order by Firstname ASC ';
return database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc, List<User> scope){
system.debug('Scope size' +scope.size());
try{
String currentUserLink = URL.getSalesforceBaseUrl().toExternalForm() + '/';
if(scope.size() >0){
for(user u: scope){
if(u.IsEmailSendToNonActive__c != true){
u.IsEmailSendToNonActive__c = true;
string[] toAddress = new string[] {u.Email};
string subject = 'Notification Of User Deactivation';
string plainBody = 'TEST'
SendEmail(toAddress,subject, plainBody, null, null );
update u;
}
}
}
}
catch(exception e){
errors.add(e);
}
}
global void finish(Database.BatchableContext bc){
//Admins email addresses
List<string> emailAdd = new List<string>();
for(AdminsEmailList__c emad : AdminsEmailList__c.getAll().values())
{
system.debug('emad.Email__c:'+emad.Email__c);
emailAdd.add(emad.Email__c);
}
List<AggregateResult> numberOfRows = [Select count(id) from user where IsEmailSendToNonActive__c=True and lastmodifieddate = today];
integer numRow = (integer)numberOfRows[0].get('expr0');
AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
FROM AsyncApexJob WHERE Id =:BC.getJobId()];
//check for errors if no error then proceed
string errorString;
for(Exception s: errors)
{
errorString = errorString + s.getMessage();
}
if(!errors.isEmpty()) {
string errSub = 'Error(s) occurred during sending emails to Non Active user batch process.';
string errBody = 'below is the error details: \n\n'+errorString;
SendEmail(emailAdd, errSub, errBody, null, null);
}
}
public void SendEmail(List<string> toEmailAdd, string subject, string body, string attchmentName, string attachment){
system.debug('toEmailAdd::'+toEmailAdd);
if(toEmailAdd != null && !toEmailAdd.isEmpty()){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(toEmailAdd);
mail.setSubject(subject);
mail.setSaveAsActivity(false);
mail.setPlainTextBody(body);
Messaging.sendEmail(new Messaging.Email[] { mail });
}
}
}
--- Schedular --
global class ScheduleSendEmailToNonActiveUsers implements Schedulable{
global void execute(SchedulableContext sc){
SendEmailtoNonActiveUsersBatch s = new SendEmailtoNonActiveUsersBatch();
database.executeBatch(s, 10);
}
}
--- TEST CLASS -----
@isTest
public class SendEmailtoNonActiveUsersBatch_Test {
@IsTest(seeAllData=true)
public static void SendEmailTest_positive()
{
User us = [Select id from User where Id = :UserInfo.getUserId()];
System.runAs(us)
{
List<user> uu = [SELECT id,Firstname,Lastname,Profile.name, email,Isactive, LastLoginDate, category__c,IsEmailSendToNonActive__c FROM User where IsActive=True and Category__c= 'Employee' and IsEmailSendToNonActive__c != true and LastLoginDate < LAST_N_DAYS:20 order by Firstname ASC Limit 10];
Test.startTest();
SendEmailtoNonActiveUsersBatch s = new SendEmailtoNonActiveUsersBatch();
database.executeBatch(s);
Test.stopTest();
}
}
}
Another observation: test class should execute DML query menstioned in test class(resulte records 10). But when I run the test class it take query mentioned in batch apex(result records 162).
All Answers
There is a chain of batches happening which can't be done in a test class apparently from the error message.
Thanks for replying. I tried that also but its not working. same error. :(
global Database.QueryLocator start(Database.BatchableContext bc) {
string query = 'SELECT id,Firstname,Lastname,Profile.name, email,Isactive, LastLoginDate, category__c,IsEmailSendToNonActive__c FROM User where IsActive=True and Category__c= \'Employee\' and IsEmailSendToNonActive__c != true and LastLoginDate < LAST_N_DAYS:20 order by Firstname ASC LIMIT 10';
return database.getQueryLocator(query);
}
below are my tests and result (which is same for all):
1) @isTest(SeeAllData = false) then in test method created 10 users. Still it takes query from batch start function. Not test data. and throw above error.
2) @isTest(SeeAllData = true) then in test method queried users with LIMIT 10. Still it takes query from batch start function. Not test data. and throw above error.
3) I ran between test.start and stop, System.schedule('ScheduleApexClassTest', CRON_EXP, new ScheduleSendEmailToNonActiveUsers()); Still it takes query from batch start function. Not test data. and throw above error.
4) I ran between test.start and stop, database.executeBatch(s, 1); Still it takes query from batch start function. Not test data. and throw above error.
In Short no luck :(
Thanks, for replies :)