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
StradaStrada 

Problems with test class for after update trigger.

Hi guys,

 

I'm wondering if anyone can help. I know this is probably something trivial that I'm missing but I have written a trigger that compares 2 amount field values in 2 different objects - Opportunity amount and Change Request amount. If these values are not equal then my trigger will force the Change Request amount to take the value of the Opportunity amount.

 

This all works fine, however, in my test class when I update the amount of the Change Request (so that it fires this update trigger), let's say change it to 150 from value 90, my assert statement keeps failing because the values are not equal. Here is a snippet of code from my test class:

 

---

Change_Request__c cr = new Change_Request__c(Summary__c = 'Test Crash Change Request', Amount__c = 90.00, Opportunity__c = myOpportunity.Id);

 

insert cr;      
        
System.assertEquals(myOpportunity.Amount, cr.Amount__c); //assert statement passes as two amounts are equal (90)
        
cr.Amount__c = 150.00;
update cr;
        
List<Change_Request__c> myCR = [Select Amount__c from Change_Request__c where id = : cr.Id];

 

System.assertEquals(myOpportunity.Amount, myCR[0].Amount__c); //failure as assert expects both values to be equal,

                                                                                                                            //but myCR[0].Amount__c = 150

---

 

So I can't figure out how to return the updated value from the trigger. My debug logs show this value of 150 getting updated to 90 in my trigger code, but no matter what I try in my test class I can't seem to achieve the same result.

 

Your help is great appreciated!

Best Answer chosen by Admin (Salesforce Developers) 
bob_buzzardbob_buzzard

If its a before trigger you just need to change the field value on the record, as the record hasn't been written to the database yet.  You'd only need DML if you were in an after trigger.

All Answers

bob_buzzardbob_buzzard

The trigger updates the record stored in the database, not your local reference to it.  Thus you'll need to query it back from the database again.  Something like:

 

Opportunity oppFromDB=[select id, Amount from Opportunity where id=:myOpportunity.id];

System.assertEquals(oppFromDB.Amount, myCR[0].Amount__c); 
                                                                                                                            

 

StradaStrada

Hi bob_buzzard,

 

Thanks for your reply - I didn't think that I needed to query the opportunity as that amount value will remain unchanged. What my trigger does is when the values don't match it will set the Change Request amount value to the value of the Opportunity amount. So I thought my querying for the updated Change Request amount is all I needed to do to get the updated amount value to use in my assert statement.

 

Will I post my full trigger and test code?

 

Thanks for your help with this - it's very much appreciated.

bob_buzzardbob_buzzard

Yeah, post the full code - I'm obviously not understanding :)

StradaStrada

Thanks a million. Here you go....

 

------------------

Trigger Code

------------------

 

trigger VerifyChangeRequestOppAmount on Change_Request__c (after insert, after update) {

List<Id> crqs = new List<Id>();
List<Opportunity> opps = new List<Opportunity>();
Double crqAmount;
Double oppAmount;

Map<Id, Change_Request__c> OppId_ChangeRequest = new Map<Id, Change_Request__c>();

for (Change_Request__c crq : Trigger.new){
        crqs.add(crq.Opportunity__c); //Very important - you need to add the field that relates change request to opportunity to id list!!
        OppId_ChangeRequest.put(crq.Opportunity__c, crq);
        crqAmount = crq.Amount__c;
    
    
    for (Opportunity opp: [Select Amount from Opportunity where Id in :crqs]) {
        
        Change_Request__c myChangeReq = OppId_ChangeRequest.get(opp.Id);
        oppAmount = opp.Amount;
    
        if (oppAmount != crqAmount){
            System.debug('Amounts not equal - Opp Amount: ' + oppAmount + ' CR Amount: ' + crqAmount);
            crqAmount = oppAmount;    //Opportunity amount is dominating so if amounts don't match assign opp amount to CR amount
            System.debug('Amounts have now been made equal - Opp Amount: ' + oppAmount + ' CR Amount: ' + crqAmount);
            
        } else {
            System.debug('Amounts are equal - Opp Amount: ' + oppAmount + ' CR Amount: ' + crqAmount);
        }
        
    }
    
}

}

 

---------------

Test Class

---------------

 

@isTest
public class TestVerifyChangeRequestOppAmount {

static testMethod void TestVerifyChangeRequestOppAmount() {
       
        //create Account
        Account myAccount = new Account (name='Test Crash Organization');
        myAccount.BillingCountry = 'Ireland';
        myAccount.Type = 'Prospect';
        myAccount.Status__c = 'Prospect';
        insert myAccount;
                
        Contact mycontact = new Contact (lastName='Test Crash Contact',Contact_Status__c = 'Pending',MailingCountry='Ireland');
        mycontact.account = myAccount;
        insert mycontact;
        
        List<Account> savedAccount = [SELECT Status__c, Type FROM Account WHERE name = 'Test Crash Organization'];
        
        // create an opportunity
        Opportunity myOpportunity = new Opportunity(name='Test Crash Opp',
                                           AccountId=savedAccount[0].id,
                                           StageName='Open',
                                           CloseDate = date.today(),
                                           Deal_Type__c = 'New Business',
                                           Interest_Driver__c = 'Product replacement',
                                           amount=90.00,
                                           Billing_Method__c = 'Monthly',
                                           Billing_Term__c = 'CC',
                                           No_of_Flyers__c = 2,
                                           No_of_Newsletters__c = 2,
                                           Service_Order_Number__c = '234234',
                                           X1k_emails__c = 2,
                                           Overage_Rate__c = 7.00,
                                           Solution_Category__c = 'New Account setup',
                                           Communication_Type__c = 'Internal Comms'
                                           );
        insert myOpportunity;
        
        Change_Request__c cr = new Change_Request__c(Summary__c = 'Test Crash Change Request', Amount__c = 90.00, Opportunity__c = myOpportunity.Id);
        insert cr;      
        
        System.assertEquals(myOpportunity.Amount, cr.Amount__c);
        
        cr.Amount__c = 150.00;
        update cr;
        
        List<Change_Request__c> myCR = [Select Amount__c from Change_Request__c where id = : cr.Id];
        System.assertEquals(myOpportunity.Amount, myCR[0].Amount__c);
        
    }

}

bob_buzzardbob_buzzard

There's a few issues with your trigger I think.  In this section:

 

for (Change_Request__c crq : Trigger.new){
        crqs.add(crq.Opportunity__c); //Very important - you need to add the field that relates change request to opportunity to id list!!
        OppId_ChangeRequest.put(crq.Opportunity__c, crq);
        crqAmount = crq.Amount__c;
    
    
      for (Opportunity opp: [Select Amount from Opportunity where Id in :crqs]) {
    
    }

 }

 You are iterating the change requests, but executng the opportunity for loop for each of them, whereas it looks like you are trying to to it for all of the crqs list.

 

You only have one crqAmount, so this wouldn't work with more than one opportunity.

 

But the main issue:

 

crqAmount = oppAmount;    //Opportunity amount is dominating so if amounts don't match assign opp amount to CR amount

 you are updating a local variable to the opportunity amount - this has no effect on any of the records in the database.  As this is an after trigger you would need to update the crq records rather than simply changing the field value.  You might want to change this to a before trigger so that the trigger records are writeable.

 

 

 

StradaStrada

Thanks for your response, my trigger started out as a before update trigger but when I couldn't get anything working I changed it to an after insert, after update trigger. Now when I change it back to a before update trigger and insert a line into my trigger to update the change request I get the following error:

 

Trigger.VerifyChangeRequestOppAmount: line 31, column 1: []

Class.TestVerifyChangeRequestOppAmount.TestVerifyChangeRequestOppAmount: line 41, column 1
08:48:18.662 (5662014000)|FATAL_ERROR|System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, VerifyChangeRequestOppAmount: execution of BeforeInsert

caused by: System.SObjectException: DML statment cannot operate on trigger.new or trigger.old

Trigger.VerifyChangeRequestOppAmount: line 31, column 1: []

 

If you can suggest a better way of doing this I would be grateful.

 

Thanks again for all your help.

bob_buzzardbob_buzzard

If its a before trigger you just need to change the field value on the record, as the record hasn't been written to the database yet.  You'd only need DML if you were in an after trigger.

This was selected as the best answer
StradaStrada

Thanks for your help bob_buzzard, now I can see the error of my ways. Sorry for my trivial questions but I'm still quite new to the apex coding side of Salesforce.

 

Thanks again for your help - it's much appreciated.

bob_buzzardbob_buzzard

No problem.  New people are welcome here!

StradaStrada

Hi again Bob,

 

Just thought you might be interested to see my final (cleaned-up) trigger:

 

-----

trigger VerifyChangeRequestOppAmount on Change_Request__c (before update) {

    List<Id> crqs = new List<Id>();
    List<Opportunity> opps = new List<Opportunity>();
    
    for (Change_Request__c crq : Trigger.new){
        
        crqs.add(crq.Opportunity__c);
        opps = [Select Amount from Opportunity where Id in :crqs]; //Obtain associated Opportunity for Change Request
            
        if (opps[0].Amount != crq.Amount__c){
            //Opportunity amount is dominating so if amounts don't match assign opp amount to CR amount
            crq.Amount__c = opps[0].Amount;    
            System.debug('Amounts have now been made equal - Opp Amount: ' + opps[0].Amount + ' CR Amount: ' + crq.Amount__c);        
        } else {
            System.debug('Amounts are equal - Opp Amount: ' + opps[0].Amount + ' CR Amount: ' + crq.Amount__c);
        }
    }    
}

-----

 

This is working fine for me now. Just thought you might like to see it and perhaps point out any other flaws that may be in there but functionality wise and for what I need to achieve it works fine.

 

Thanks again for all your help!

StradaStrada

Hi Bob,

 

I'm just wondering if I can ask you one more question. When I tried to deploy my code to live it failed to deploy as another before update Trigger caused this exception:

 

-----

08:27:35.022 (6022998000)|EXCEPTION_THROWN|[11]|System.DmlException: Update failed. First exception on row 0 with id a0PP0000001ORtKMAW; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, VerifyChangeRequestOppAmount: execution of BeforeUpdate

caused by: System.ListException: List index out of bounds: 0

Trigger.VerifyChangeRequestOppAmount: line 11, column 1: []
08:27:35.023 (6023874000)|USER_DEBUG|[16]|DEBUG|error: Update failed. First exception on row 0 with id a0PP0000001ORtKMAW; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, VerifyChangeRequestOppAmount: execution of BeforeUpdate

caused by: System.ListException: List index out of bounds: 0

-----

 

The reason I didn't come across this in my Sandbox is because the other trigger code wasn't up-to-date. Once I updated this code and ran the test from the other Trigger's test class it threw the error. The actual trigger and test class that I have been working on (VerifyChangeRequestOppAmount) doesn't register a failure when I run a test on it's own test class, the failure only happens when I run the test on the other before update trigger (ChangeRequestCompleted) .

 

Is this happening because I'm running 2 before update triggers on the same object? If so can you suggest how to overcome this problem? Here is my trigger code again that passes it's own test but is causing the test on the other trigger to fail:

 

-----

trigger VerifyChangeRequestOppAmount on Change_Request__c (before update) {

    List<Id> crqs = new List<Id>();
    List<Opportunity> opps = new List<Opportunity>();
    
    for (Change_Request__c crq : Trigger.new){
        
        crqs.add(crq.Opportunity__c);
        opps = [Select Amount from Opportunity where Id in :crqs]; //Obtain associated Opportunity for Change Request
            
        if (opps[0].Amount != crq.Amount__c){  //THIS IS LINE 11 WHERE THE EXCEPTION IS BEING THROWN.
            //Opportunity amount is dominating so if amounts don't match assign opp amount to CR amount
            crq.Amount__c = opps[0].Amount;    
            System.debug('Amounts have now been made equal - Opp Amount: ' + opps[0].Amount + ' CR Amount: ' + crq.Amount__c);        
        } else {
            System.debug('Amounts are equal - Opp Amount: ' + opps[0].Amount + ' CR Amount: ' + crq.Amount__c);
        }
    }    
}

-----

 

Thanks again for all your help with this.

bob_buzzardbob_buzzard

Two triggers on the same object shouldn't be a problem - the only downside is that you can't control the ordering.  

 

The error looks to me like there is a change request without associated opportunity.  Its good practice to defend against these conditions in code anyway.  I think the following should do the trick:

 

trigger VerifyChangeRequestOppAmount on Change_Request__c (before update) {

    List<Id> crqs = new List<Id>();
    List<Opportunity> opps = new List<Opportunity>();
    
    for (Change_Request__c crq : Trigger.new){
        
        crqs.add(crq.Opportunity__c);
        opps = [Select Amount from Opportunity where Id in :crqs]; //Obtain associated Opportunity for Change Request
            
        if (opps.size()>0)
        {
           if (opps[0].Amount != crq.Amount__c){  //THIS IS LINE 11 WHERE THE EXCEPTION IS BEING THROWN.
               //Opportunity amount is dominating so if amounts don't match assign opp amount to CR amount
               crq.Amount__c = opps[0].Amount;    
               System.debug('Amounts have now been made equal - Opp Amount: ' + opps[0].Amount + ' CR Amount: ' + crq.Amount__c);        
           } else {
               System.debug('Amounts are equal - Opp Amount: ' + opps[0].Amount + ' CR Amount: ' + crq.Amount__c);
           }
        }
    }    
}

 

StradaStrada

bob_buzzard you are the man! That has worked so I don't get the failure any more in my Sandbox. Wish me luck deploying to live!

 

Thanks again for your help, and for being lightening fast with your response! I really appreciate it Bob.