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
DeafForceDeafForce 

Help with Test Class

Hi everyone,

 

I found a trigger online and modified it slightly. It simply edit/saves the account whenever I modify a related contact. Workflows and triggers get fired once the account has been modified afterwards.

However, I am having trouble with creating the test class. To be honest I always have issues with the "after insert, after update" test classes.

 

Can you guide me in the right direction to get the test class sorted? I checked the docs but if someone got a sample test class for after insert, after update, that would be great.

 

Here is the code:

 

trigger UpdateAccount on Contact (after update,after insert) {


        Contact [] con;
        con= Trigger.new;

set<Id> accIds = new Set <ID>();

for (Contact  ir : con) {
        
    accIds.add(ir.AccountId);

Map <ID, Contact > irforaccs = new Map <ID, Contact > (
    [select Id, accountId from Contact 
    where accountId in :accIds]);

Map<ID, Account> accsToUpdate = new Map<ID, Account> (
    [select Id  from Account
    where Id in :accIds]);

for (Account acc : accsToUpdate.values()) {
    acc.id = acc.id ;
    update acc;
}}}

 

 

If you believe you have an easier solution, then please let me know!

 

Your help is very much appreciated!

Thanks in advance,

Christian

 

Best Answer chosen by Admin (Salesforce Developers) 
zachbarkleyzachbarkley

Hi Christian,

 

Please accept this first example of only 1 primary contact per account. It's a good example for starters. I will post your requirement of multiple contacts per account shorty. Please do look at the test class now as that will not change.

 

The Trigger Handler

 

public class Contact_HDL_AIAU{
    public void OnInsert(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }      
    public void OnUpdate(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }  
    private void updateRecord(List<Contact> upRec,List<Contact> oldRec) {
        /******************************************************************
        * Do not put a DML Statement in any FOR statements
        ********************************************************************/
      	LIST<Account> AccountsToUpdate = new LIST<Account>{};
      	for (Contact R:upRec){
      		if(R.AccountId!=null){
      			Account ThisAccount = new Account(
      				Id=R.AccountId
      				,Primary_Contact_Email__c = R.Email
      			);	
      			AccountsToUpdate.ADD(ThisAccount);
      		}
      	}
      	if(!AccountsToUpdate.IsEmpty()){
      		UPDATE AccountsToUpdate;
      	}
    }
}

 

The Trigger

 

trigger Contact_AIAU on Contact (after insert, after update) {
    Contact_HDL_AIAU hdl = new Contact_HDL_AIAU();    
    if(Trigger.isInsert && Trigger.isAfter) {
        hdl.OnInsert(Trigger.new,Trigger.old);
    }else if(Trigger.isUpdate && Trigger.isAfter) { 
        hdl.OnUpdate(Trigger.new,Trigger.old);
    }
}

 

 

The Test Class

 

/******************************************************************
NAME YOUR TEST CLASS SOMETHING SIMILAR TO YOUR CLASS SO ITS EASY
TO SPOT IT WHEN YOU GO TO ADD TO AN OUTBOUND CHANGE SET
********************************************************************/
@isTest
private class Contact_HDL_AIAU_TC{

    /******************************************************************
    Declare all record variables here so you can use them in any test method. 
    Examples: 
        private static Account A1;
        private static Contact C1;
    ********************************************************************/
  
    private static Account AC1;
    private static Account AC2;
    private static Account AC3;
    private static Contact C1;
    private static Contact C2;
    private static Contact C3;
    
    /******************************************************************
    Write your Test Methods Here. You can write as many Test Methods as
    you like. Each Test method uses it's own governing limits. 
    ********************************************************************/
 
    private static testMethod void T1(){    
        
        /******************************************************************
        * START TEST
        *******************************************************************/
        Test.StartTest();
        
        /******************************************************************
        * GOOD TO RUN AS USER
        *******************************************************************/
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
        System.runAs ( thisUser ) {
            /*********************************************************
	        * PUT YOUR TEST RECORD METHODS HERE - MAKE SURE THAT 
	        * YOU PUT THEM IN THE ORDER THAT A USER WOULD ENTER THEM
	        * EG. Accounts must be inserted before contacts!  
	        **********************************************************/
            insertTestAccounts();
            insertTestContacts();
            
            /*********************************************************
	        * Lets now write some code that will signify a user is editing
	        * a current contact to be a primary contact
	        **********************************************************/
            List<Contact> UpdateContact2 = [SELECT Id,Email,Is_A_Primary_Contact__c FROM Contact WHERE Id=:C2.Id LIMIT 1];
            UpdateContact2[0].Is_A_Primary_Contact__c = true;
            UPDATE UpdateContact2; // AGAIN THIS WILL RUN OVER ANY AFTER UPDATE CODE TO BE COVERED
            
        }  
        
        /******************************************************************
        * STOP TEST
        ********************************************************************/
        Test.StopTest();
    }    
    
     private static testMethod void T2(){    
        
        /******************************************************************
        * START TEST
        *******************************************************************/
        Test.StartTest();
        
        /******************************************************************
        * GOOD TO RUN AS USER
        *******************************************************************/
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
        System.runAs ( thisUser ) {
            /*********************************************************
	        * You might have different data to insert here which may cover
	        * Alternate scenarios.  
	        **********************************************************/
            //insertTestAccountsAlternateInfo();
            //insertTestContactsAlternateInfo();

            
        }  
        
        /******************************************************************
        * STOP TEST
        ********************************************************************/
        Test.StopTest();
    }    
    
    
     /******************************************************************
     * YOUR RECORD INSERT METHODS
     ********************************************************************/ 
     public static void insertTestAccounts(){

        List<Account> remRecords= [SELECT Id FROM Account];  
        DELETE remRecords;
        System.assertEquals(0,[SELECT count() FROM Account]);
                     
        List<Account> Accounts = new List<Account>();      
        
        AC1 = NEW Account(
             Name='Account 1'
            ,Primary_Contact_Email__c=null
        );
   
        Accounts.add(AC1);
        
        AC2 = NEW Account(
             Name='Account 2'
            ,Primary_Contact_Email__c=null
        );
   
        Accounts.add(AC2);    

        AC3 = NEW Account(
             Name='Account 3'
            ,Primary_Contact_Email__c=null
        );
   
        Accounts.add(AC3);
        
        INSERT Accounts;
        UPDATE Accounts;
       
        System.assertEquals(3,[SELECT count() FROM Account]);

    }  
     public static void insertTestContacts(){

        List<Contact> remRecords= [SELECT Id FROM Contact];  
        DELETE remRecords;
        System.assertEquals(0,[SELECT count() FROM Contact]);
                     
        List<Contact> Contacts = new List<Contact>();      
        
        C1 = NEW Contact(
             FirstName='Contact'
            ,LastName='1'
            ,Email='contact1@test.com'
            ,AccountId = AC1.Id
            ,Is_A_Primary_Contact=false
        );
        C2 = NEW Contact(
             FirstName='Contact'
            ,LastName='2'
            ,Email='contact2@test.com'
            ,AccountId = AC1.Id
            ,Is_A_Primary_Contact=false
        );
        C3 = NEW Contact(
             FirstName='Contact'
            ,LastName='3'
            ,Email='contact3@test.com'
            ,AccountId = AC1.Id
            ,Is_A_Primary_Contact=true
        );
        Contacts.add(C1);
        Contacts.add(C2);
        Contacts.add(C3);
        
        INSERT Contacts; // THIS IS ACTUALLY THE LINE WHICH WILL COVER YOUR AFTER INSERT
        UPDATE Contacts; // JUST CHEATING THE CODE COVERAGE TO RUN OVER YOUR AFTER UPDATE!!!
       
        System.assertEquals(3,[SELECT count() FROM Contact]);

    }   
}

All Answers

zachbarkleyzachbarkley

Hi Christian,


Would you mind telling me what your main outcome for the trigger is?

 

Eg. I am wanting to update the account which is assigned to a contract with ....

 

I apologise but I am unable to make out what you are trying to acheive. Please post here what you're trying to achieve and i'll submit a test class for you and complete the below classes.

 

Best practice for triggers is to use a handler class to perform your requirements.

 

1. Create your trigger handler class by going to Your Name | Setup | Apex Classes | New
 

public class Contact_HDL_AIAU{
    public void OnInsert(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }      
    public void OnUpdate(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }  
    private void updateRecord(List<Contact> upRec,List<Contact> oldRec) {
        /******************************************************************
        * IDENTIFY NEW RECORD
        ********************************************************************/
        Boolean NewRecord=false;
        if(oldRec==null){
            NewRecord=true;
        }
        /******************************************************************
        * Write your requierments here - Do not put a DML Statement in any FOR statements
        ********************************************************************/
      	
      	for (Contact R.upRec){
      		// YOUR CODE
      		
      	}
    }
}

 

 

2. Create your trigger by going to Your Name | Setup | Customize | Contacts | Triggers

 

trigger Contact_AIAU on Contact (after insert, after update) {
    Contact_HDL_AIAU hdl = new Contact_HDL_AIAU();    
    if(Trigger.isInsert && Trigger.isAfter) {
        hdl.OnInsert(Trigger.new,Trigger.old);
    }else if(Trigger.isUpdate && Trigger.isAfter) { 
        hdl.OnUpdate(Trigger.new,Trigger.old);
    }
}

 

 

zachbarkleyzachbarkley

Just to confirm, "edit/saves the account whenever I modify a related contact"

 

Would you mind telling me why you are wanting to UPDATE the account record when a contact is modified? So i know the best solution to provide you.

 

DeafForceDeafForce

Hi,

 

Sure let me provide you with more information.

 

In one of my previous posts I mentioned the scenario already. We retrieve all email addresses from the related "primary" contacts into a txt box on the account. That's needed as we want to email them all at once when a ticket is created. This works all fine.

If someone makes a contact a "primary" contact, then the accounts should get updated so that the trigger on the account fires again pulling in the email address from the primary contacts.

Basically I just wanna close the loop so that nobody has to go back to the account and edit/saves it to simply retrieve the emails as it would be an additional (and to me pointless) step the account manager would have to do.

 

Hope that helps.

 

Thanks,

Christian

zachbarkleyzachbarkley

So just to confirm, would a single account have 1 primary contact only? or could a single account have more than 1 primary contact that you wish to email at the same time?

 

DeafForceDeafForce

An account can have many primary contacts

zachbarkleyzachbarkley

Hi Christian,

 

Please accept this first example of only 1 primary contact per account. It's a good example for starters. I will post your requirement of multiple contacts per account shorty. Please do look at the test class now as that will not change.

 

The Trigger Handler

 

public class Contact_HDL_AIAU{
    public void OnInsert(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }      
    public void OnUpdate(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }  
    private void updateRecord(List<Contact> upRec,List<Contact> oldRec) {
        /******************************************************************
        * Do not put a DML Statement in any FOR statements
        ********************************************************************/
      	LIST<Account> AccountsToUpdate = new LIST<Account>{};
      	for (Contact R:upRec){
      		if(R.AccountId!=null){
      			Account ThisAccount = new Account(
      				Id=R.AccountId
      				,Primary_Contact_Email__c = R.Email
      			);	
      			AccountsToUpdate.ADD(ThisAccount);
      		}
      	}
      	if(!AccountsToUpdate.IsEmpty()){
      		UPDATE AccountsToUpdate;
      	}
    }
}

 

The Trigger

 

trigger Contact_AIAU on Contact (after insert, after update) {
    Contact_HDL_AIAU hdl = new Contact_HDL_AIAU();    
    if(Trigger.isInsert && Trigger.isAfter) {
        hdl.OnInsert(Trigger.new,Trigger.old);
    }else if(Trigger.isUpdate && Trigger.isAfter) { 
        hdl.OnUpdate(Trigger.new,Trigger.old);
    }
}

 

 

The Test Class

 

/******************************************************************
NAME YOUR TEST CLASS SOMETHING SIMILAR TO YOUR CLASS SO ITS EASY
TO SPOT IT WHEN YOU GO TO ADD TO AN OUTBOUND CHANGE SET
********************************************************************/
@isTest
private class Contact_HDL_AIAU_TC{

    /******************************************************************
    Declare all record variables here so you can use them in any test method. 
    Examples: 
        private static Account A1;
        private static Contact C1;
    ********************************************************************/
  
    private static Account AC1;
    private static Account AC2;
    private static Account AC3;
    private static Contact C1;
    private static Contact C2;
    private static Contact C3;
    
    /******************************************************************
    Write your Test Methods Here. You can write as many Test Methods as
    you like. Each Test method uses it's own governing limits. 
    ********************************************************************/
 
    private static testMethod void T1(){    
        
        /******************************************************************
        * START TEST
        *******************************************************************/
        Test.StartTest();
        
        /******************************************************************
        * GOOD TO RUN AS USER
        *******************************************************************/
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
        System.runAs ( thisUser ) {
            /*********************************************************
	        * PUT YOUR TEST RECORD METHODS HERE - MAKE SURE THAT 
	        * YOU PUT THEM IN THE ORDER THAT A USER WOULD ENTER THEM
	        * EG. Accounts must be inserted before contacts!  
	        **********************************************************/
            insertTestAccounts();
            insertTestContacts();
            
            /*********************************************************
	        * Lets now write some code that will signify a user is editing
	        * a current contact to be a primary contact
	        **********************************************************/
            List<Contact> UpdateContact2 = [SELECT Id,Email,Is_A_Primary_Contact__c FROM Contact WHERE Id=:C2.Id LIMIT 1];
            UpdateContact2[0].Is_A_Primary_Contact__c = true;
            UPDATE UpdateContact2; // AGAIN THIS WILL RUN OVER ANY AFTER UPDATE CODE TO BE COVERED
            
        }  
        
        /******************************************************************
        * STOP TEST
        ********************************************************************/
        Test.StopTest();
    }    
    
     private static testMethod void T2(){    
        
        /******************************************************************
        * START TEST
        *******************************************************************/
        Test.StartTest();
        
        /******************************************************************
        * GOOD TO RUN AS USER
        *******************************************************************/
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
        System.runAs ( thisUser ) {
            /*********************************************************
	        * You might have different data to insert here which may cover
	        * Alternate scenarios.  
	        **********************************************************/
            //insertTestAccountsAlternateInfo();
            //insertTestContactsAlternateInfo();

            
        }  
        
        /******************************************************************
        * STOP TEST
        ********************************************************************/
        Test.StopTest();
    }    
    
    
     /******************************************************************
     * YOUR RECORD INSERT METHODS
     ********************************************************************/ 
     public static void insertTestAccounts(){

        List<Account> remRecords= [SELECT Id FROM Account];  
        DELETE remRecords;
        System.assertEquals(0,[SELECT count() FROM Account]);
                     
        List<Account> Accounts = new List<Account>();      
        
        AC1 = NEW Account(
             Name='Account 1'
            ,Primary_Contact_Email__c=null
        );
   
        Accounts.add(AC1);
        
        AC2 = NEW Account(
             Name='Account 2'
            ,Primary_Contact_Email__c=null
        );
   
        Accounts.add(AC2);    

        AC3 = NEW Account(
             Name='Account 3'
            ,Primary_Contact_Email__c=null
        );
   
        Accounts.add(AC3);
        
        INSERT Accounts;
        UPDATE Accounts;
       
        System.assertEquals(3,[SELECT count() FROM Account]);

    }  
     public static void insertTestContacts(){

        List<Contact> remRecords= [SELECT Id FROM Contact];  
        DELETE remRecords;
        System.assertEquals(0,[SELECT count() FROM Contact]);
                     
        List<Contact> Contacts = new List<Contact>();      
        
        C1 = NEW Contact(
             FirstName='Contact'
            ,LastName='1'
            ,Email='contact1@test.com'
            ,AccountId = AC1.Id
            ,Is_A_Primary_Contact=false
        );
        C2 = NEW Contact(
             FirstName='Contact'
            ,LastName='2'
            ,Email='contact2@test.com'
            ,AccountId = AC1.Id
            ,Is_A_Primary_Contact=false
        );
        C3 = NEW Contact(
             FirstName='Contact'
            ,LastName='3'
            ,Email='contact3@test.com'
            ,AccountId = AC1.Id
            ,Is_A_Primary_Contact=true
        );
        Contacts.add(C1);
        Contacts.add(C2);
        Contacts.add(C3);
        
        INSERT Contacts; // THIS IS ACTUALLY THE LINE WHICH WILL COVER YOUR AFTER INSERT
        UPDATE Contacts; // JUST CHEATING THE CODE COVERAGE TO RUN OVER YOUR AFTER UPDATE!!!
       
        System.assertEquals(3,[SELECT count() FROM Contact]);

    }   
}
This was selected as the best answer
DeafForceDeafForce

Thanks for that! Thanks as well for the comments on the test class! The trigger and class I could insert. If I try to insert the test class though I get an error stating: 

 

Error: Compile Error: Invalid bind expression type of SOBJECT:Contact for column of type Id at line 51 column 108

 

Any idea? 

 

zachbarkleyzachbarkley

Oh silly me.. try this new LINE (replacing Is_A_Primary_Contact__c with your own custom field of course)

 

List<Contact> UpdateContact2 = [SELECT Id,Email,Is_A_Primary_Contact__c FROM Contact WHERE Id=:C2.Id LIMIT 1];

 

zachbarkleyzachbarkley

Hi Christian,

 

Please try the following code for a multiple primary contact example. The trigger and test class remain the same. I'm sure somone else might have a better way of doing this, please feel free to post if you do :-)

 

public class Contact_HDL_AIAU{
    public void OnInsert(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }      
    public void OnUpdate(List<Contact> upRec,List<Contact> oldRec){
        updateRecord(upRec,oldRec); 
    }  
    private void updateRecord(List<Contact> upRec,List<Contact> oldRec) {
        /******************************************************************
        * Do not put a DML Statement in any FOR statements
        ********************************************************************/
      	LIST<Account> AccountsToUpdate = new LIST<Account>{};
      	
      	List<Contact> FindAccountContacts = [SELECT 
  			Id,AccountId,Email
		FROM Contact WHERE Id IN :Trigger.newMap.keySet()];
      	
      	for(Contact R:upRec){
      		if(R.AccountId!=null){
      			for(Contact R1:FindAccountContacts){
      				
      				String EmailAddressStr='';
      				AccountAlreadyAdded=false;
      				for(Account ATO:AccountsToUpdate){
      					if(ATO.Id == R1.AccountId){
      						AccountAlreadyAdded=true;
      					}
      				}
      				if(!AccountAlreadyAdded){
      					for(Contact R2:FindAccountContacts){
      						if(R1.Email!=null){
      							EmailAddressStr = EmailAddressStr+';'+R2.Email;	
      						}
      					}
      					if(EmailAddressStr!=''){ 
				            EmailAddressStr= EmailAddressStr.mid(1, EmailAddressStr.length());
				        }
      					Account ThisAccount = new Account(
		      				Id=R.AccountId
		      				,Primary_Contact_Email__c = EmailAddressStr
		      			);	
		      			AccountsToUpdate.ADD(ThisAccount);
      				}	
      				
      			}
      			
      		}
      	}
      	if(!AccountsToUpdate.IsEmpty()){
      		UPDATE AccountsToUpdate;
      	}
    }
}

 

 

Let me know how you go.

 

DeafForceDeafForce

That works like a charm! Thank you so much for sorting this out and providing me with the additional information!!

 

Have a great day and thank you again!

Christian

zachbarkleyzachbarkley

Your welcome Christian :-)