+ Start a Discussion
MoosecoutureMoosecouture 

Test Execution taking a long time

I think since I have two after update triggers.  I am thinking that they are some how conflicting and causing everything to run longer.  Does anybody know of a way to clean this code up so that these will not cause us to get close to our limits?  The First code is actually our attempt at resolving salesforce's issue with not giving access to trigger assignment rules natively from the webpage when creating a case using chatter actions or visual workflow.  The reason it is not just after insert like many I have seen out there is because sometimes we need the case to have child objects attached before we assign it to a queue.  We need this to be initiated at the time of when the case has been finished with information entry.

The Second code selection is going to show that we have a particular field that we added to the case and it looks to the account name and contact first name to make sure that they match the "C_S_Customer_Number__c" entered into the field so that it will return these values on the case.
trigger UpdateAssignmentGlobalActions on Case (after update, after insert) {
    try{
    List<Case> listCase = new List<Case>{};
    if(!ProcessorControl.inFutureContext){
    ProcessorControl.inFutureContext = true;
    List<Id> caseIds = new List<Id>{};
    AssignmentRule AR = new AssignmentRule();
    AR = [select id from AssignmentRule where SobjectType = 'Case' and Active = true limit 1];
    Database.DMLOptions dmlOpts = new Database.DMLOptions();
    dmlOpts.assignmentRuleHeader.assignmentRuleId= AR.id;
    for(Case cse: Trigger.New)
    {
            caseIds.add(cse.Id);
    }
    

    for(Case cse: [Select Id, Assignment_Override__c from Case where Id in :caseIds])
    {
        If(cse.Assignment_Override__c == true)
        {
            cse.setOptions(dmlOpts);
            listCase.add(cse);
            cse.put('Assignment_Override__c',false);
        }
    }

    }
    update listCase;
    } catch(exception ex){}
}
@isTest
private class ChatterAssignmentRuleOverrideTest{
   static testMethod void verifyAssignmentOfCasesFromTrigger(){
    List<Case> cases = new List<Case>{};
    RecordType RecType = new RecordType ();
    RecType = [SELECT Id FROM RecordType WHERE SobjectType = 'Case' and IsActive = true and Name = 'CRM Request' LIMIT 1];    
    
    for(Integer i = 0; i < 200; i++){
        Case c = new Case(Subject = 'Test Case' + i, Issue_Type__c = 'CRM Issue', Assignment_Override__c = false, RecordType = RecType );
        cases.add(c);
    }
    insert Cases;
    
    List<Case> CaseList = new List<Case>{};
    For(Case Cse: [Select Id from Case where Assignment_Override__c = false])
    {
    cse.put('Assignment_Override__c',true);
    CaseList.add(cse);
    }
    test.startTest();
        
    update CaseList;
    test.stopTest();
        
    List<Case> insertedCases = [SELECT Subject, Description, OwnerId 
                                      FROM Case
                                      WHERE Id IN :cases];
        

    for(Case c : insertedCases){
      System.assertEquals(
      '00GE0000001VU9f' , 
        c.OwnerId);
    }
}
}
Here is the old code that seems to be igniting issues with limits.
trigger CaseAccountContact on Case (before insert, before update) {
try{
    if(!ProcessorControl.inFutureContext){
        ProcessorControl.inFutureContext = true;
        AccountContactHelper.findAccountContactByCustomerNumber(Trigger.new, false); 
    } else {
        ProcessorControl.inFutureContext = false;
        }
    }
    catch(Exception ex){}
}
public with sharing class AccountContactHelper {

    private static String customerNumber = 'C_S_Customer_Number__c'; 
    private static String CustomAccountField = 'Account__c'; 
    private static String CustomContactField = 'Contact__c';
    private static String StandardAccountField = 'AccountId';
    private static String StandardContactField = 'ContactId';

    public static boolean findAccountContactByCustomerNumber(List<SObject> records,boolean isCustom){

        Map<String,SObject> customerNumberMap   = new Map<String,SObject>();
        Map<Account,Contact> acctContacts       = new Map<Account,Contact>();
      
        String accountField = StandardAccountField;
        String contactField = StandardContactField;
        
        if(isCustom){
            accountField = CustomAccountField;
            contactField = CustomContactField;
        }
        

        for(SObject s : records){
            if(s.get(customerNumber) != null && s.get(customerNumber) != '')    
                customerNumberMap.put(String.valueof(s.get(customerNumber)),s);
        }
        
        if(customerNumberMap.size() == 0)
            return true; 
        
        for(Account a : [Select Id, Name, (Select Id, LastName, FirstName from Contacts) from Account]){
            if(a.Name.length() >= 5){ 
                acctContacts.put(a,null);
                for(Contact c : a.Contacts){
                    if(c.FirstName.length() >= 5 && (c.FirstName.subString(0,5) == a.Name.subString(0,5))) 
                        acctContacts.put(a,c); 
                }
            }
            
        }
        
        for(String s : customerNumberMap.keySet()){
            for(Account a : acctContacts.keySet())
                if(a.Name.subString(0,5)  == s){ 
                    customerNumberMap.get(s).put(accountField,a.Id);
                    if(acctContacts.get(a) != null) 
                        customerNumberMap.get(s).put(contactField,acctContacts.get(a).Id);                  
                    break; 
                }
        }

        return true;
    }


}
Here is the test class:
@isTest
private class TestAccountContactHelper {
    
    static testMethod void testCaseTrigger() {
        loadAccountContactData(); 
        List<Case> cases = new List<Case>(); 
        for(Integer i=0;i<200;i++){
            Case c = new Case(Status='New',Origin='Web',C_S_Customer_Number__c=+String.valueof(30000 + i));
            cases.add(c);
        }
        Test.startTest();
            insert cases; 
        Test.stopTest();
        cases = [Select Id, AccountId,ContactId,Account.Name,Contact.FirstName,C_S_Customer_Number__c from Case]; 
        system.assertEquals(200,cases.size()); 
        for(Case c : cases){
            system.assertEquals(c.C_S_Customer_Number__c,c.Account.Name.subString(0,5)); 
            system.assertEquals(c.C_S_Customer_Number__c,c.Contact.FirstName.subString(0,5)); 
        }
    }
    static void loadAccountContactData(){
        List<Account> accts = new List<Account>();
        List<Contact> cons  = new List<Contact>();
        for(Integer i=0;i<200;i++){
            Account a = new Account(Name=String.valueof(30000 + i));
            accts.add(a);
        }
        insert accts;
        for(Integer i=0;i<200;i++){
            Contact c = new Contact(LastName='Test',FirstName=String.valueof(30000 + i),AccountId=accts[i].Id);
            cons.add(c);
        }
        insert cons;
    }
}
Here were the issues we were having before adding "ProcessorControl.inFutureContext"
Maximum CPU time: 8783 out of 10000 ******* CLOSE TO LIMIT
Number of query rows: 26538 out of 50000 ******* CLOSE TO LIMIT
Here is where we still stand after this implementation
Maximum CPU time: 5911 out of 10000 ******* CLOSE TO LIMIT
Number of query rows: 17818 out of 50000
This implementation is taking less time but it should be working faster than this.

Thank you in advance,
Craig
Best Answer chosen by Moosecouture
PratikPratik (Salesforce Developers) 
Hi,

As per the Trigger best practices, you should write a trigger per object and call the diffrerent operations through Classs methods. 

As you have 2 triggers, you can consolidate them into one and identify the triggring events on the basis of Trigger context variables like
trigger.isbefore, trigger.isafter, trigger.isinsert etc...
https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_context_variables.htm

Hope this will guide you.

Thanks,
Pratik