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
fiona gentryfiona gentry 

Do we write test method for email notification sending as part of batch

Hi Gurus

Do we write  test method for  email notification sending as part of batch,in here at below finish stage there is code for email sending ,so question is do I need to write test class for email sending functionality as we?? if yes,any ideas how to write a class for below?
global class leadUpdateBatch implements Database.batchable<sobject>,Database.stateful{
    public Map<id,id> newLeadTaskIdMap = new map<id,id>();
    public Map<id,Task> taskMap = new Map<id,Task>();
    
    String VIP1 = Label.B2C_VIP_API_User;
    String VIP2 = Label.B2C_VIP_AAL_API_User;
    String VIP3 = Label.B2C_VIP_SWITCH_API_User;
    
    Id VIPInboundTaskId = Schema.SObjectType.Task.getRecordTypeInfosByName().get('VIP Inbound').getRecordTypeId();
    Id VIPOutboundTaskId = Schema.SObjectType.Task.getRecordTypeInfosByName().get('VIP Outbound').getRecordTypeId();
    Id OutBoundCallingTaskId = Schema.SObjectType.Task.getRecordTypeInfosByName().get('Outbound Call').getRecordTypeId();
    Id CDTaskId = Schema.SObjectType.Task.getRecordTypeInfosByName().get('ILC Task').getRecordTypeId();   
    global List<String> errorMessages = new List<String>();
    Global List<String> failedRecIdList =new List<String>();
    global Set<String> faliedIdSet=new Set<String>();
    public DateTime dt = Datetime.now().addMinutes(-integer.valueof(Label.LeadUpdateBatchInterval));
    String dispo = NULL;
    String LEAD = 'Lead';    
    
    
	Map<string,string> taskLeadFieldMap=new Map<string,string>
		{'Call_Type__c'=>'Call_Type__c', 'Disposition__c'=>'Disposition__c',
		'FollowUpLastmodified__c'=>'PilotTaskFollowup__c', 'Reason_for_Call__c'=>'Reason_for_Call__c',
		'Customer_Budget__c'=>'Customer_Budget__c', 
		'Time_Frame_for_Purchase__c'=>'Time_Frame_for_Purchase__c','TOM_Order_Number__c'=>'TOM_Order__c',
		'Chat_Engagement_Id__c'=>'Chat_Engagement_Id__c','New_Device__c'=>'Device__c',
		'Current_Carrier__c'=>'Current_Carrier__c','Current_Monthly_Bill__c'=>'Monthly_Bill__c',
		'Lines__c'=>'Lines__c', 'Savings__c'=>'Savings__c', 'Customer_Type__c'=>'Customer_Type__c',
		'T_Mobile_ID__c'=>'T_Mobile_ID__c','Customer_Contact_Phone_Number__c'=>'Phone',
		'Zip_Code__c'=>'Zip__c', 'Follow_Up_Date_Time__c'=>'Follow_Up_Date_Time__c',
		'First_Call_Attempt_Date__c'=>'First_Call_Attempt_Date__c', 
		'Second_Call_Attempt_Date__c'=>'Second_Call_Attempt__c',
        'Agent_Manager_Role__c'=>'Dispositioned_Agent_parent_role__c',
        'Agent_Name__c'=>'Dispositoned_Agent_Name__c'};
		
    global Database.QueryLocator start(Database.BatchableContext bc){

        
        return Database.getQueryLocator('Select Id,whoid,Call_Type__c,Agent_Name__c,Agent_Manager_Role__c,FollowUpLastmodified__c,disposition__c,Follow_up_Date_Time__c,Reason_for_Call__c,Customer_Budget__c,Time_Frame_for_Purchase__c,TOM_Order_Number__c,Chat_Engagement_ID__c,New_Device__c,Current_Carrier__c,Current_Monthly_Bill__c,Lines__c,Savings__c,Customer_Type__c,T_Mobile_ID__c,Customer_Contact_Phone_Number__c,Zip_Code__c,First_Call_Attempt_Date__c,Second_Call_Attempt_Date__c,RecordTypeId  from task where LastModifiedDate >=:dt and WHO.Type =: Lead and OwnerId !=:VIP1 and OwnerId !=:VIP2 and OwnerId !=:VIP3 and disposition__c !=:dispo and (RecordTypeId =:VIPInboundTaskId or RecordTypeId =:CDTaskId or RecordTypeId =:VIPOutboundTaskId or RecordTypeId =:OutBoundCallingTaskId) ORDER BY LastModifiedDate DESC');
        //return Database.getQueryLocator('Select Id,whoid,Call_Type__c,FollowUpLastmodified__c,disposition__c,Follow_up_Date_Time__c,Reason_for_Call__c,Customer_Budget__c,Time_Frame_for_Purchase__c,TOM_Order_Number__c,Chat_Engagement_ID__c,New_Device__c,Current_Carrier__c,Current_Monthly_Bill__c,Lines__c,Savings__c,Customer_Type__c,T_Mobile_ID__c,Customer_Contact_Phone_Number__c,Zip_Code__c,First_Call_Attempt_Date__c,Second_Call_Attempt_Date__c,RecordTypeId  from task where LastModifiedDate >=:dt and whoid in (select id from Lead) and OwnerId !=:VIP1 and OwnerId !=:VIP2 and OwnerId !=:VIP3 and (RecordTypeId =:VIPInboundTaskId or RecordTypeId =:CDTaskId or RecordTypeId =:VIPOutboundTaskId ) ORDER BY LastModifiedDate DESC');
        
    }
    
    global void execute(Database.BatchableContext bc,List<Task> scope){ 
        
        for(task task : scope){                       
            if(!newLeadTaskIdMap.containsKey(task.whoId)){
            	newLeadTaskIdMap.put(task.whoId,task.id);              
            }
			taskMap.put(task.id,task);
        }
		
        if(!newLeadTaskIdMap.isEmpty()){
            List<Lead> updateLeads=new List<Lead>();
            Boolean hasChanged=false;
            List<Lead> leadList = [select id,
                                   			Call_Type__c,Disposition__c,PilotTaskFollowup__c,
                                   			Reason_for_Call__c,Dispositioned_Agent_parent_role__c,Dispositoned_Agent_Name__c,Customer_Budget__c,Time_Frame_for_Purchase__c,
                                   			TOM_Order__c,Chat_Engagement_Id__c,Device__c,Current_Carrier__c,
                                   			Monthly_Bill__c,Lines__c,Savings__c,Customer_Type__c,T_Mobile_ID__c,
                                   			Phone,Zip__c,Follow_Up_Date_Time__c,First_Call_Attempt_Date__c,Second_Call_Attempt__c
                                   			from Lead where id IN:newLeadTaskIdMap.keySet()];
			
            for(Lead lead : leadList)
			{
                //faliedIdSet.add(ld.Id);
                Task taskRecord = taskMap.get(newLeadTaskIdMap.get(lead.id));
                hasChanged=false;
				for(string taskField:taskLeadFieldMap.keyset())
				{
                    System.debug('==taskRecord.get(taskField)=='+taskRecord.get(taskField));
                    System.debug('==lead.get(taskLeadFieldMap.get(taskField))=='+lead.get(taskLeadFieldMap.get(taskField)));
					if(taskRecord.get(taskField)!=NULL && taskRecord.get(taskField) != lead.get(taskLeadFieldMap.get(taskField)))
                    {                        
                        System.debug('==taskLeadFieldMap.get(taskField)=='+taskLeadFieldMap.get(taskField));                        
						lead.put(taskLeadFieldMap.get(taskField), taskRecord.get(taskField));
						hasChanged=true;
					}					
				}
                if(hasChanged)
					updateLeads.add(lead);
			}
				
            if(!updateLeads.isEmpty() ){
                System.debug('updateLeads==='+updateLeads);
                
                Database.SaveResult[] srList = database.update(updateLeads, false);
                System.debug('===srList==='+srList);
				String errMsg;
                // Iterate through each returned result
                for (Database.SaveResult sr : srList){
					errMsg='';
                    if (!sr.isSuccess()) {
                        System.debug('Successfully  ' + sr.getId());
                        faliedIdSet.add(sr.getId());
						// Operation failed, so get all errors                
                        for(Database.Error err : sr.getErrors()) {                                             
                            System.debug(err.getStatusCode() + ': ' + err.getMessage());  
                            errMsg+= '-'+ err.getMessage();                     
						}
						failedRecIdList.add(errMsg);
                    }
                }
            }
            
        } 
    }
    
    
    global void finish(Database.BatchableContext bc){
        
        
        AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
        FROM AsyncApexJob WHERE Id =:BC.getJobId()];
        
        //Get the list of Emails from Custom setting and send notification   
        Email_Notifications__c emaillist = Email_Notifications__c.getValues('LeadUpdateBatchEmails');
        System.debug('emaillist ==== > '+emaillist);
        List<String> userList = emaillist.Email_Address__c.split(',');
          
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        
        mail.setToAddresses(userList);
        mail.setSubject('LeadUpdateBatch Status - ' + a.Status);
        mail.setSaveAsActivity(false);
        //mail.setPlainTextBody('Failed Records Ids: ' +faliedIdSet);
        //mail.setPlainTextBody('Error Message : ' +failedRecIdList);
        mail.setPlainTextBody('Failed Record Details:    ' +faliedIdSet+failedRecIdList + '\n' + 'Job Completed Date :    ' + a.CompletedDate + '\n' + 'Job Status :      ' + a.Status + '\n'+ 'Total Job Items processed :      ' + a.TotalJobItems + '\n'+ 'Number of Job Items processed :       ' + a.JobItemsProcessed + '\n' + 'Number of Failures :       '+ a.NumberOfErrors );
        //+ '\n' + 'Number of Error Messages ' + errorMessages.size() + '\n' +'Error Message' + String.join(errorMessages, '\n'));
        
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
  
   
}

 
Best Answer chosen by fiona gentry
AnudeepAnudeep (Salesforce Developers) 
Hi Fiona, 

Yes, we need to write unit tests for code that sends an email. Here is an example
 
public with sharing class EmailUtility 
{
	public static void sendPlainTextEmail(List<String> toAddresses, String subject, String body)
	{    	
    	Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
		mail.settoAddresses(toAddresses);
		mail.setSubject(subject);
		mail.setPlainTextBody(body);
		Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
	}
}

We need to validate if the email is sent through the test class
 
@isTest
private class EmailUtilityTest 
{
    @isTest
    static void testEmailUtility()
    {
        Test.StartTest();
        EmailUtility.sendPlainTextEmail(new List<String>{'test@test.com'}, 'Unit Test X', 'Unit Test');
        Integer invocations = Limits.getEmailInvocations();
        Test.stopTest();
 
        System.assertEquals(1, invocations, 'An email has not been sent');
    }
}

NOTE: The code provided is an example. You'll need to review and make modifications for your organization.

Let me know if it helps. If it does, please mark this answer as Best. It may help others in the community. Thank You!