You need to sign in to do that
Don't have an account?
jonathanbernddf20131.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
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'); } }
All Answers
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
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.