0

I've got a trigger in place to count how many times a field has been updated:

trigger IncrementClosedCounter on Opportunity (before update) {
    Opportunity[] oldOpp = Trigger.New;
    Opportunity[] newOpp = Trigger.Old;
    for(Integer i = 0; i<oldOpp.size(); i++){
        if(!((Date)oldOpp[i].get('CloseDate')).isSameDay((Date)newOpp[i].get('CloseDate'))){
            oldOpp[i].put('Closed_Date_Change_Count__c', 
(Decimal)oldOpp[i].get('Closed_Date_Change_Count__c')+1);}}}

It works as expected in the Salesforce interface. When I update the Close Date, the Closed Date Change Count field increments by 1.

However, when I execute my test class for the trigger, it appears to update by 2. Most of the posts I've read on this phenomenon talk about workflows accidentally firing the trigger twice, but I believe that if that was what was occurring here, the trigger would also fire twice in normal usage.

My test class code is here:

@isTest
private class TestOppCloseDateIncrement {
    @isTest static void TestIncrementingCloseDateChangeCounter(){
        Account acct = new Account(Name='Test Acct2');
        insert acct;
        Opportunity opp = new Opportunity(Name=acct.Name+' Opp',
                                     StageName='1 - Qualification',
                                 CloseDate=System.today().addMonths(1),
                                     AccountId=acct.Id,
                                     Closed_Date_Change_Count__c=0);
        insert opp;

        Integer pre_count =Integer.valueOf(opp.get('Closed_Date_Change_Count__c'));
        Test.startTest();
        opp.CloseDate = System.today().addMonths(2);
        update opp;
        Test.stopTest();

        List<Opportunity> oppsList=new List<Opportunity>{opp};
        List<Opportunity> updatedOpps=[SELECT Id, Name, Closed_Date_Change_Count__c
            FROM Opportunity
            WHERE Id=:oppsList[0].Id];
        system.assertEquals(1,updatedOpps.size());
        for(Opportunity record:updatedOpps){

system.assertEquals(pre_count+1,record.Closed_Date_Change_Count__c);
    }}}
5
  • Do you have an after insert trigger on Opportunity that fires an update event? More broadly, is this the only trigger in your org on Opportunity, including managed packages? Have you tried putting a System.debug() in your trigger and inspecting the logs to see when it's being invoked?
    – David Reed
    Jun 18, 2018 at 19:12
  • As David said it could be related to before/after insert functionality. In Salesforce interface have you tested creating a new Opp and editing the Closed Date?
    – Ranga
    Jun 18, 2018 at 20:42
  • Debug logs are your friend here. Did you happen to review them???
    – Eric
    Jun 19, 2018 at 4:16
  • There may be other triggers on Opportunity. When I put debug lines in the trigger, I am not seeing any debug logs in the developer console even after adjusting the debug log trace flags.
    – pyg
    Jun 26, 2018 at 18:13
  • Additionally, when I use my trigger through the salesforce interface, it works as desired.
    – pyg
    Jun 26, 2018 at 18:14

1 Answer 1

0

Can't suggest much why is it firing twice without seeing the workflow configuration.

However, if there is a field update from workflow on the object at the time of update/insert, the trigger will fire again.

If you want to restrict your trigger to run once, you may have to use the following design pattern

  1. create a class

    public class RecursiveCheck {
    
        private static boolean firstRun = true; 
        public static boolean isFirstRun(){
            if(firstRun){
                firstRun=false;
                return true;
            }
            else{
                return firstRun;
            }
        }
    }
    
  2. Use it in the trigger

    trigger IncrementClosedCounter on Opportunity (before update) {
    
        //return from the trigger if its a second run
        if (!RecursiveCheck.isFirstRun()) {
            return;
        }
    
        Opportunity[] oldOpp = Trigger.New;
        Opportunity[] newOpp = Trigger.Old;
        for(Integer i = 0; i<oldOpp.size(); i++){
            if(!((Date)oldOpp[i].get('CloseDate')).isSameDay((Date)newOpp[i].get('CloseDate'))){
                oldOpp[i].put('Closed_Date_Change_Count__c',(Decimal)oldOpp[i].get('Closed_Date_Change_Count__c')+1);
            }
        }
    }
    
1
  • 2
    this pattern has issues and will fail if the transaction has 201+ records as the static flag will prevent execution of the trigger for record 201, 202, ... = This use case can occur with direct Apex DML of more than 200 records or bulk API or platform event ingestion under high volumes
    – cropredy
    Jun 18, 2018 at 23:08

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.