+ Start a Discussion
Developer.mikie.Apex.StudentDeveloper.mikie.Apex.Student 

Help writing Test code for Email trigger and class and cleaning up redundant code

Hey there,

I have an email trigger and a class in which I use to send emails to all the contacts associated with an account when a service (which is also associated with the account) reaches stage 4. I have written test codes before, but I do not even know where to begin to write test code for an email trigger. please help.  


This is my trigger: 

trigger SendEmailtocontact on Service__c (after Update) {

    List<String> lcontactEmails = new List<String>();
    Set<Id> sIds = new Set<Id>();
  
    for(Service__c qItr : Trigger.new){
        if(Trigger.isUpdate){
            if(Trigger.oldmap.get(qItr.id).Service_Stage__c != qItr.Service_Stage__c && qItr.Service_Stage__c.containsIgnoreCase('Stage 4')){
                sIds.add(qItr.id);
            }
        }
        else if(Trigger.isInsert){
            if(Trigger.newMap.get(qItr.id).Service_Stage__c.containsIgnoreCase('Stage 4')){
                sIds.add(qItr.id);
            }
        }
    }
    for(Account accItr : [SELECT id,(SELECT id FROM Contacts) FROM Account WHERE id IN (SELECT Account__c FROM Service__c WHERE Id IN: sIds)]){
        for(Contact con : accItr.contacts){
            if(!String.isBlank(con.id)){
                lcontactEmails.add(con.id);
            }
        }
        if(!lcontactEmails.isEmpty()){
         EmailHandler.sendEmail(lcontactEmails); 
        }
    }
}

This is my class:

public class EmailHandler{

    public static void sendEmail (List<String> contactids){
    
        Messaging.MassEmailMessage mail = new Messaging.MassEmailMessage();
        //set the email properties
        mail.setTargetObjectIds(contactids);
        mail.setSenderDisplayName('Destiny Customer Service');
        mail.setTemplateId('00XO0000000MEyP'); //Id of the Email Template
    
        //send the email
        Messaging.sendEmail(new Messaging.MassEmailMessage[] { mail } );
      }
}


I was also hoping to maybe get some pointers on how I may clean up this code a bit, as I changed it a bit and I am sure there is a fair bit of redundant lines in there.

Thank you in advance for your help

Kind regards,

Mikie
Best Answer chosen by Developer.mikie.Apex.Student
Ankit Gupta@ DeveloperAnkit Gupta@ Developer

Hi,

Try the below modified code (In Bold)
//////////////// Test class ///////////////////

@istest
private class SendEmailtocontact {
static testMethod void SendEmailtocontact()
{
account a1=new account(name='test');
insert a1;
contact con=new contact(lastname='con',firstname='test',email='test@gmail.com',accountid=a1.id);
insert con;
Service__c serviceobj=new Service__c(Service_Stage__c='Stage 1',Account__c=a1.id);
insert serviceobj;
serviceobj.Service_Stage__c='Stage 4';
update serviceobj;
}
}

In previous Test Class I haven't passed the account id for the contact that's why the EmailHandler desn't executed as the contact list was null.

Try the above one and I am sure that you will get 100% from Email Handler and more than 90% for trigger .

All Answers

Ankit Gupta@ DeveloperAnkit Gupta@ Developer
Hi,

Try the below modified code
trigger SendEmailtocontact on Service__c (after Update)
{
    List<String> lcontactEmails = new List<String>();
    Set<Id> sIds = new Set<Id>();
//Added
    Set<ID> accIds = new Set<ID>();
    for(Service__c qItr : Trigger.new)
{
        if(Trigger.isUpdate)
  {
            if(Trigger.oldmap.get(qItr.id).Service_Stage__c != qItr.Service_Stage__c && qItr.Service_Stage__c.containsIgnoreCase('Stage 4'))
   {
                sIds.add(qItr.id);
    //Added
    accIds.add(qItr.Account__c);
            }
        }
  //Will Never Execute as trigger will fire only if a record is updated
        else if(Trigger.isInsert)
  {
            if(Trigger.newMap.get(qItr.id).Service_Stage__c.containsIgnoreCase('Stage 4'))
   {
                sIds.add(qItr.id);
            }
        }
    }
// Modified
    //for(Account accItr : [SELECT id,(SELECT id FROM Contacts) FROM Account WHERE id IN (SELECT Account__c FROM Service__c WHERE Id IN: sIds)])
for(Account accItr : [SELECT id,(SELECT id FROM Contacts) FROM Account WHERE id IN : accIds])

{
        for(Contact con : accItr.contacts)
  {
            if(!String.isBlank(con.id))
   {
                lcontactEmails.add(con.id);
            }
        }
       // No need to put this condition here.
  /*if(!lcontactEmails.isEmpty())
  {
   EmailHandler.sendEmail(lcontactEmails);
  }*/   

    }
//Put this here
if(!lcontactEmails.isEmpty())
{
        EmailHandler.sendEmail(lcontactEmails);
    }
}

//////////////// Test class ///////////////////
//Below is the test class sample code.please modified as per your requirment and datamodel
// This will execute your trigger logic and the EmailHandler class logic
@istest
private class SendEmailtocontact {
static testMethod void SendEmailtocontact()
{
account a1=new account(name='tes');
insert a1;
contact con=new contact(lastname='con',firstname='test',email='test@gmail.com');
insert con;
Service__c serviceobj=new Service__c(Service_Stage__c='Stage 1',Account__c=a1.id);
insert serviceobj;
serviceobj.Service_Stage__c='Stage 4';
update Service_Stage__c;
}
}

Developer.mikie.Apex.StudentDeveloper.mikie.Apex.Student

Hey Ankit,

Thank you so much for your help. I am very impressed with your ability to analyze and write something like that so fast. I imput your trigger and it still works perfectly so thankyou. The test saved aswell after I changed the -update service_stage__c- to -Update serviceobj-. 

 

However, upon running the test, although i got a pass I was left with a code coverage of 64% in the trigger and 0 in the emailhandler class. You mentioned that i would have to modify as per requirements of my data model. Would you be able to give me an example of what i need to do to get 100%?

Once again thank you so much for your time.

Ankit Gupta@ DeveloperAnkit Gupta@ Developer

Hi,

Try the below modified code (In Bold)
//////////////// Test class ///////////////////

@istest
private class SendEmailtocontact {
static testMethod void SendEmailtocontact()
{
account a1=new account(name='test');
insert a1;
contact con=new contact(lastname='con',firstname='test',email='test@gmail.com',accountid=a1.id);
insert con;
Service__c serviceobj=new Service__c(Service_Stage__c='Stage 1',Account__c=a1.id);
insert serviceobj;
serviceobj.Service_Stage__c='Stage 4';
update serviceobj;
}
}

In previous Test Class I haven't passed the account id for the contact that's why the EmailHandler desn't executed as the contact list was null.

Try the above one and I am sure that you will get 100% from Email Handler and more than 90% for trigger .
This was selected as the best answer
Developer.mikie.Apex.StudentDeveloper.mikie.Apex.Student
Thankyou Ankit,

100% on class and 82% on trigger. You are a lifesaver.