3

I have an afterupdate trigger which was getting executed twice upon update of a field as well as fieldupdate action through workflow. In order to stop this, I had to use recursive stopping mechanism to stop the second iteration of trigger execution. It however, drastically reduced trigger coded coverage (from 100% to 33%). Below is my code -

Main Trigger -

trigger InsUpdCaseComment on Case (after update) {

// System.debug('In InsUpdCaseComment....1');

 List <CaseComment__c> caseComments = new List<CaseComment__c>();  

 if (Trigger.isAfter) {
 // System.debug('In InsUpdCaseComment....2');
            if (Trigger.isUpdate) {
            // System.debug('In InsUpdCaseComment....3');
               if(checkRecursive.runOnce())
               {
                   for(Case HandoffRecord : trigger.New){
                                          // Handoff Details
                     if (HandoffRecord.Handoff_To_Timezone__c != Trigger.oldMap.get(HandoffRecord.Id).Handoff_To_Timezone__c) {
                                    // System.debug('Handoff comments - Start');

                                    CaseComment__c caseComment = new CaseComment__c();
                                    caseComment.Parent__c = HandoffRecord.Id;
                                    // String dtNew = HandoffRecord.DateTime_Put_Into_Queue__c.format('MMM/dd/yyyy');
                                    // String timNew = HandoffRecord.DateTime_Put_Into_Queue__c.format('h:m a');
                                    caseComment.Comment__c = 'Handoff Details: \n'+'Handoff Action Required: '+ HandoffRecord.Handoff_Instructions__c + ' ,\n' + ' Handoff Reason: '+ HandoffRecord.Handoff_Reason__c + '\n' + ' Handoff Time Action is Required: '+ HandoffRecord.Handoff_Time_Action_Required__c +'\n' + ' Handoff Timezone: '+ HandoffRecord.Handoff_To_Timezone__c;

                                    caseComment.Public__c = false;
                                    caseComments.add(caseComment);
                                    System.debug('Handoff comments - End');
                    } 
                   // insert caseComments;    
                                      if (HandoffRecord.Portal_Escalation_Comments__c != Trigger.oldMap.get(HandoffRecord.Id).Portal_Escalation_Comments__c) {
                                    // System.debug('Escalations comments - Start');
                                    CaseComment__c caseComment = new CaseComment__c();
                                    caseComment.Parent__c = HandoffRecord.Id;
                                    // String dtNew = HandoffRecord.Escalated_Date__c.format('MMM/dd/yyyy');
                                    // String timNew = HandoffRecord.DateTime_Put_Into_Queue__c.format('h:m a');
                                    // System.debug('Recent Updates = ' + HandoffRecord.Elevated_Most_Recent_Update__c);
                                    caseComment.Comment__c = 'Escalation Details: \n' + 'Portal Escalation Comments: ' + HandoffRecord.Portal_Escalation_Comments__c;

                                    caseComment.Public__c = false;
                                    caseComments.add(caseComment);
                                    // System.debug('Portal comments - End');
                     }

                     if (HandoffRecord.Next_Expected_Update__c != Trigger.oldMap.get(HandoffRecord.Id).Next_Expected_Update__c) {
                                    // System.debug('Escalations comments - Start');
                                    CaseComment__c caseComment = new CaseComment__c();
                                    caseComment.Parent__c = HandoffRecord.Id;
                                    // String dtNew = HandoffRecord.Escalated_Date__c.format('MMM/dd/yyyy');
                                    // String timNew = HandoffRecord.DateTime_Put_Into_Queue__c.format('h:m a');
                                    // System.debug('Recent Updates = ' + HandoffRecord.Elevated_Most_Recent_Update__c);
                                    caseComment.Comment__c = 'Escalation Details: \n' + 'Next Expected Update: '+ HandoffRecord.Next_Expected_Update__c;

                                    caseComment.Public__c = false;
                                    caseComments.add(caseComment);
                                    // System.debug('Next Expected Update - End');
                     }


                     if (HandoffRecord.Elevated_Most_Recent_Update__c != Trigger.oldMap.get(HandoffRecord.Id).Elevated_Most_Recent_Update__c) {
                                    // System.debug('Escalations comments - Start');
                                    CaseComment__c caseComment = new CaseComment__c();
                                    caseComment.Parent__c = HandoffRecord.Id;
                                    // String dtNew = HandoffRecord.Escalated_Date__c.format('MMM/dd/yyyy');
                                    // String timNew = HandoffRecord.DateTime_Put_Into_Queue__c.format('h:m a');
                                    // System.debug('Recent Updates = ' + HandoffRecord.Elevated_Most_Recent_Update__c);
                                    caseComment.Comment__c = 'Escalation Details: \n'+'Latest Updates/Next Steps: '+ HandoffRecord.Elevated_Most_Recent_Update__c ;

                                    caseComment.Public__c = false;
                                    caseComments.add(caseComment);

                                    // System.debug('Latest updates - End');
                      } 

                    // insert caseComments;
                    // } 
                }
             }  
     }
     // System.debug('Before Insert');
     insert caseComments;
   }
}

Recursive Class –

public Class checkRecursive{
    private static boolean run = true;
    public static boolean runOnce(){
        if(run){
             run=false;
             return true;
        }    
        else{
        return run;
        }
    }
}

Test Class –

@istest(oninstall=false SeeAllData=false)
private class InsUpdCaseComment_Test {

    static testMethod void theTests(){

        //Create sample test data
        Account a1 = new Account(Name='test account 1',Industry='Energy');
        insert a1;         

        Case c1 = new Case(Subject='New Case 1',Status='Unassigned',Priority='P3 - Normal',AccountId =a1.Id);
        c1.SuppliedEmail = 'test@idunno.com';
        c1.Description = 'customer_name:Fake Contact \n customer_email:test@test.com \n serial_number:123456789 \n';
        insert c1;

        c1.Handoff_To_Timezone__c = 'AMER WEST (PST/PDT)';
        c1.Handoff_Instructions__c = 'Test Instructions';
        c1.Handoff_Reason__c = 'Regular work to align with customer business hours';
        c1.Handoff_Time_Action_Required__c = '05/31/2015 12:00';

        c1.Elevated_Most_Recent_Update__c = 'Recent Update';
        c1.Escalation_Status__c = 'Waiting on Account Team';
        c1.Next_Expected_Update__c = 'Test next expected update';

        update c1;
        // System.assert(1<2,'Now it should work..');
        System.debug('Test Class...1');


        List<Case> CList  =  [Select Elevated_Most_Recent_Update__c, Escalation_Status__c, Next_Expected_Update__c from Case WHERE Id = :c1.Id];
        for(Case Record : CList){
          System.assert(Record.Next_Expected_Update__c != null,'Case Updated');   
          System.assert(Record.Elevated_Most_Recent_Update__c != null,'Case Updated');
          System.assert(Record.Escalation_Status__c != null,'Case Updated');
        }

        List<Case> CList2  =  [Select Handoff_To_Timezone__c, Handoff_Instructions__c, Handoff_Time_Action_Required__c from Case WHERE Id = :c1.Id];
        for(Case Record : CList2){
          System.assert(Record.Handoff_To_Timezone__c != null,'Case Updated');   
          System.assert(Record.Handoff_Instructions__c != null,'Case Updated');
          System.assert(Record.Handoff_Time_Action_Required__c != null,'Case Updated');
        }

        c1.Elevated_Most_Recent_Update__c = 'Recent Update # 2';
        update c1;

        System.debug('Test Class...2');
        List<CaseComment__c> CommentResultList  =  [Select Comment__c from CaseComment__c WHERE Parent__c = :c1.Id];
        for(CaseComment__c CommentUpdate : CommentResultList){
          System.assert(CommentUpdate.Comment__c != null,'Comments Inserted');   
        }
        System.debug('Test Class...3');


    }
}

I will really appreciate if someone can suggest how to improve code coverage. If I done use recursive stoping mechanism, then my trigger gets invoked twice which I don't want.

Thanks in advance. -Sanjay

3
  • Are you by any chance using the same recursive logic for an insert trigger?
    – Prady
    Jun 5 '15 at 6:50
  • Take a look at your debug logs and see what's happening. Read How do I start to debug my own Apex code?.
    – crmprogdev
    Jun 6 '15 at 2:41
  • Voting to reopen this because it seems pretty clear what issue Sanjay is running into, not sure I understand why this was closed.
    – Jenny B
    Jun 10 '15 at 14:46
2

Take a look at the Triggers and Order of Execution, it sounds like the insert of the case is triggering your workflow rule which is causing your trigger to run and setting the recursive flag during the insert part of your test. Since it is a test method that static variable will stay set so when you actually are updating the record it thinks it already ran. One suggestion is by allowing your test method to reset the run flag. Another suggestion is to deal with recursion in a different way, take a look at Chris's answer here.

When you save a record with an insert, update, or upsert statement, Salesforce performs the following events in order.

  1. If the record was updated with workflow field updates, fires before update triggers and after update triggers one more time (and only one more time), in addition to standard validations. Custom validation rules are not run again.

UPDATE: To test a private method you can use the TestVisible Notation as described in the help docs here:

Example class:

public class TestVisibleExample {
    // Private member variable
    @TestVisible private static Integer recordNumber = 1;

    // Private method
    @TestVisible private static void updateRecord(String name) {
        // Do something
    }
}

Example Test:

@isTest
private class TestVisibleExampleTest {
    @isTest static void test1() {
        // Access private variable annotated with TestVisible
        Integer i = TestVisibleExample.recordNumber;
        System.assertEquals(1, i);

        // Access private method annotated with TestVisible
        TestVisibleExample.updateRecord('RecordName');
        // Perform some verification
    }
}    
3
  • Your suggestion is - "One suggestion is by allowing your test method to reset the run flag." . How do I do it ? I tried to set it like this - checkRecursive.run = true; But it gives me "Variable is not visible" error. How do I reset the run flag ? Jun 7 '15 at 23:04
  • @SanjayWadge I added an update to my answer with how to use the TestVisible notation.
    – Jenny B
    Jun 8 '15 at 0:34
  • @SanjayWadge were you able to get your test working?
    – Jenny B
    Jun 11 '15 at 12:10
0

In your checkRecursive class, add another method to reset the variables to allow triggers to re-execute - that is, simulating what a real user would see if they were clicking Save, waiting for a response, updating a field, and clicking save again

public Class checkRecursive{
private static boolean run = true;
public static boolean runOnce(){
    if(run){
         run=false;
         return true;
    }    
    else{
    return run;
    }
}
public static void resetAll(){
     run = true;
} 
}

Then in the test class, after insert just call this method to reset the vairable. Do this again, if you need to fire your trigger again.

checkRecursive.resetAll();
c1.Handoff_To_Timezone__c = 'AMER WEST (PST/PDT)';
c1.Handoff_Instructions__c = 'Test Instructions';
c1.Handoff_Reason__c = 'Regular work to align with customer business hours';
update c1
-1
if(checkRecursive.runOnce() || test.isRunningTest()){
    //paste your code here
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.