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
jonathanbernddf20131.387825590468351E12jonathanbernddf20131.387825590468351E12 

Test Class - creating unexpected record

Hi folks
Still learning. Got a dilemma. I have a test class that seems like it should work, and I have a class and trigger that does work in a sandbox. However, if I remove this clause from the class - if(!firstcall && newOpp[0].Name != 'Trigger') {  //can add if needed 
  //System.debug('Exiting method to update OPportunity Stage History because of !firstcall');
    return;}
    else {firstcall=false;}

the update isn't called. If I put it back the update creates an extra record with a date that should not be there.  Another way the after update fails is if I change the name to something other than Trigger in my Test Class. [I did want to do bulk testing, but as I failed I simplified it down to this one test record].  Any help would be greatly appreciated.

Here is the code for the trigger
trigger OppStageHistory on Opportunity (after insert, before update, after update) {

    if(Trigger.isInsert) {
        OppStageHistory.createOppStageHistory(Trigger.new);
    }
    if(Trigger.isUpdate) {
        for (Opportunity newOpp: Trigger.new)  {
            Integer i = 0;
            if(newOpp.StageName != Trigger.old[i].StageName) {
                OppStageHistory.updOppStageHistory(Trigger.old, Trigger.new);
            }
            i++;
        }
    }
}
Here is the code for the class 
public with sharing class OppStageHistory {

  //Initialize Static Variable
  public Static Boolean firstcall=True;    
  
  //Method to insert new Opportunity Stage History record with brand new Opportunity
  public static void updOppStageHistory(List<Opportunity> oldOpp, List<Opportunity> newOpp){

  if(!firstcall && newOpp[0].Name != 'Trigger') {  //can add if needed  
  //System.debug('Exiting method to update OPportunity Stage History because of !firstcall');
    return;}
    else {firstcall=false;}
    
   //Declare a set of the Ids in this update
   Set<Id> oppStageIds = new Set<Id>();
   for (Opportunity oppO : oldOpp) {
   //Grab the Ids from the opp List
   oppStageIds.add(oppO.Id);
   }

   //Declare a list of Opportunity Stage History
   List <Opportunity_Stage_History__c> prevOpshList = new List <Opportunity_Stage_History__c> ();
   
   //Fill the list with records that match the Id from the trigger and has a Null Completion Date
   prevOpshList = [SELECT Id, Name, Stage__c, Start_Date__c, Completion_Date__c FROM Opportunity_Stage_History__c 
                   WHERE Opportunity__c IN :oppStageIds AND Completion_Date__c = NULL]; 
                   
   //For each record in prevOpshList, set the Completion date
   for(Opportunity_Stage_History__c prevOpsh : prevOpshList) {
       prevOpsh.Completion_Date__c = date.TODAY();
    }
       
       //Update the rows in the list
       try {
           update prevOpshList;
           }
           catch (DmlException e) {
                      // Process exception here
           }
    //Declare a new List of Opportunity Stage History
    List <Opportunity_Stage_History__c> opsh = new List <Opportunity_Stage_History__c> ();
    for(Opportunity oppN: newOpp) {
              integer i = 0;   //Keeps oldOpp in sync with oppN which is newOpp 
              System.debug('oldOpp Stage is ' + oldOpp[i].StageName + '-- oppN.Stage is  ' + oppN.StageName);
              if(oppN.StageName <> oldOpp[i].StageName && oldOpp[i].StageName <> NULL) {
                   Opportunity_Stage_History__c newOpsh = new Opportunity_Stage_History__c();
                   newOpsh.Stage__c = oppN.StageName;
                   newOpsh.Start_Date__c = date.TODAY();
                   newOpsh.Opportunity__c = oppN.Id;
          
                   //System.debug('adding ' + String.valueOf(oppN.Id) + ' to List newOpsh');
                   opsh.add(newOpsh);
                 } else { //This handles the exeption when the previous Stage was blank but the Opportunity has been created with no stage
                     
                       if(oppN.StageName <> oldOpp[i].StageName) {
                           Opportunity_Stage_History__c newOpsh = new Opportunity_Stage_History__c();
                           newOpsh.Stage__c = oppN.StageName;
                           newOpsh.Start_Date__c = date.TODAY();
                           newOpsh.Opportunity__c = oppN.Id;
          
                           opsh.add(newOpsh);
                           i = i + 1;
                         }

                       } // end of else
               } // end of for loop oppN 
               //Insert the new rows
               insert opsh; 
  } //end of updOppStageHistory Method                     

  public static void createOppStageHistory(List<Opportunity> newOpp)
  {
   if(!firstcall) {
     System.debug('Exiting updOppStageHistory because of !firstcall');
     return;}
     else {firstcall=false;}
   
   List <Opportunity_Stage_History__c> opsh = new List <Opportunity_Stage_History__c> ();
   for(Opportunity oppN: newOpp) {
          Opportunity_Stage_History__c newOpsh = new Opportunity_Stage_History__c();
      
         //Set Values for New Opportunity
             if(oppN.StageName <> NULL && oppN.StageName <> '--None--')
             {
                newOpsh.Stage__c = oppN.StageName;
                newOpsh.Start_Date__c = date.TODAY();
                newOpsh.Opportunity__c = oppN.Id;
       
                opsh.add(newOpsh);
             }
          }
    insert opsh;
  }
 
}
Here is the code for the Test class (PS, when I leave the class as is, there is a duplication of the debug at line 44).
@isTest
public class TestOppStageHistory {
    
    //Start method 1 - insert new
    static testmethod void createInsOppData() {
        
        //Create an opportunity
        Opportunity insOpp = new Opportunity(
        Name = 'Trigger',
        StageName = 'Qualification/Prospecting',
        Probability = 1,
        CloseDate = date.TODAY() + 10,
        Type = 'New Business');
        
        //Run test
        Test.startTest();
        
        insert insOpp;

        Test.stopTest();
      
        //Test to see if opportunity stage history record was created
        List<Opportunity> insTestOpps = [Select Id, StageName FROM Opportunity WHERE Id = :insOpp.Id];
        String stval1 = insTestOpps[0].Id;   
        System.debug('Value of Id in Opportunity in record is ' + stval1);
            
        Opportunity_Stage_History__c newOppsh = [Select Id, Opportunity__c, Stage__c, Start_Date__c, Completion_Date__c 
                                                 FROM Opportunity_Stage_History__c WHERE Opportunity__c = :insOpp.Id];

        System.assertEquals(newOppsh.Stage__c, insOpp.StageName, 'Did not get the expected Stage__c value');
        System.assertEquals(newOppsh.Start_Date__c, date.TODAY(), 'Did not get the expected date today()');
        System.assertEquals(newOppsh.Completion_Date__c, NULL, 'Did not get the expected completion date value null');
        System.assertEquals(newOppsh.Opportunity__c, insOpp.Id, 'Did not get related to correct Opportunity parent record');
            
        //Do we have the right values?
        List<Opportunity_Stage_History__c> insertedShRecs= [SELECT Id, Stage__c, Start_Date__c, Completion_Date__c, Opportunity__c
                                                            FROM Opportunity_Stage_History__c WHERE Opportunity__c = : insOpp.Id ];
        System.debug('The number of recs in the list is ' + insertedShRecs.size());
        String stval2 = insertedShRecs[0].Stage__c;   
        System.debug('Value of Stage__c in record is ' + stval2);
        
        //End method 1
    }

    //Start method 2 - update existing
    static testmethod void createUpdOppData() {
        
        
        //Create an opportunity
        Opportunity insNewOpp = new Opportunity(
        Name = 'Trigger',
        StageName = 'Qualification/Prospecting',
        Probability = 1,
        CloseDate = date.TODAY() + 10,
        Type = 'New Business');
        
               
        //Test.startTest();
        insert insNewOpp;
        //Test.stopTest();

        
        String stval3 = insNewOpp.Id;   
        System.debug('Value of Id in Opportunity in record is ' + stval3); 
        
       
        
        Opportunity_Stage_History__c oldOsh = [SELECT Id, Completion_Date__c, Stage__c, Start_Date__c FROM Opportunity_Stage_History__c 
                                                WHERE stage__c = :insNewOpp.StageName AND Completion_Date__c = Null];
        
        String stval4 = oldOsh.Id;   
        System.debug('Value of Id in Old Stage History in record is ' + stval4);  
        System.assertEquals(oldOsh.Stage__c, insNewOpp.StageName);
        System.assertEquals(oldOsh.Start_Date__c, date.TODAY());
        
        
        //Run test 2 - update existing opportunity
        Opportunity updOpp = [SELECT Id, StageName FROM Opportunity WHERE Id = :insNewOpp.Id AND StageName = :insNewOpp.StageName];
        
        String stval5 = updOpp.Id;   
        System.debug('Value of Id in Opportunity in record is ' + stval5);
        
       
        Test.startTest();
        updOpp.StageName = 'Needs Analysis';
        

        update updOpp; 
        Test.stopTest();
        
        /*String stval5 = insNewOpp.StageName;
        System.debug('Value of StageName in updOpp record is '+stval5);*/
        
        //Did trigger update old stage history?
        List<Opportunity_Stage_History__c> updatedShRecs= [SELECT Id, Stage__c, Start_Date__c, Completion_Date__c, Opportunity__c
                                                           FROM Opportunity_Stage_History__c WHERE Opportunity__c = : updOpp.Id];
                                                           
        String stval6 = updatedShRecs[0].Id;   
        System.debug('Value of Id in Old Stage History in record is ' + stval6);  
        
        String stval7 = updatedShRecs[1].Id;   
        System.debug('Value of Id in New Stage History in record is ' + stval7);  
        
        System.assertEquals(updatedShRecs[0].Stage__c, oldOsh.Stage__c, 'Did not get expected Stage__c value');
        System.assertEquals(updatedShRecs[0].Completion_Date__c, date.TODAY(), 'Completion Date was not updated from null to today()');
        
        //Did trigger kick off new stage history rec?
        List<Opportunity_Stage_History__c> insertedShRecs= [SELECT Id, Stage__c, Start_Date__c, Completion_Date__c, Opportunity__c
                                                           FROM Opportunity_Stage_History__c WHERE Stage__c = : updOpp.StageName
                                                           AND Completion_Date__c = null];
        
        System.assertEquals(insertedShRecs[0].Stage__c, 'Needs Analysis', 'Did not get new value of Stage__c - Needs Analysis');
        System.assertEquals(insertedShRecs[0].Completion_Date__c, null, 'Did not get expected blank completion date');
        System.assertEquals(insertedShRecs[0].Start_Date__c, date.TODAY(), 'Did not get expected start date of today');
        


    }    
    
}


Best Answer chosen by jonathanbernddf20131.387825590468351E12
jonathanbernddf20131.387825590468351E12jonathanbernddf20131.387825590468351E12
Actually, i do need to iterate twice through the group, but I'm trying to rewrite the whole thing now.:)

All Answers

Hargobind_SinghHargobind_Singh
Hi, 

Any specific reason why you want your trigger to run on both before and after update  ? This would run the trigger twice on any update transaction. 

Can you run it once, either before or after ? it should take care of your double-execution issue. 

Also, instead of using the Opportunity name "Trigger" to see if your code is being called by test, you can use Test.isRunningTest(), example here: 

https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_test.htm#apex_System_Test_isRunningTest
 
Hargobind_SinghHargobind_Singh
Am reading through your code, seems like you are trying to add a record to Opportunity Stage History table whenever stage is changing, along-with change-date. 

In that case, just running the trigger on After Update should be enough ? Can you elaborate on the use-case to run both before and after-update. 

Also, your trigger line 7, you have a loop, but on line 10, you are passing the whole List-collection (trigger.new) to your method, which means if your trigger is called for bulk insert of 10 records, the loop will run 10 times, and your class seems to be handling the list and executing logic, so it will run 10 times as well, creating duplicate records for sure... you might want to handle the list either in trigger, or in your class, but not at both places. 

jonathanbernddf20131.387825590468351E12jonathanbernddf20131.387825590468351E12
Actually, i do need to iterate twice through the group, but I'm trying to rewrite the whole thing now.:)
This was selected as the best answer