1

I am writing my first trigger & class. I need a field to sync between 2 objects: Account (parent) & Opportunity (child). The field is a picklist named "Brand__c" on the Account tab, and "Subtype__c" on the Opportunity tab. I have created a trigger on each object. The triggers work perfectly when I test them in the sandbox, but when I try to run the test class, I'm getting the error "System.AssertException: Assertion Failed: Expected: InnLink, Actual: InnVite". So I don't think my triggers are working in the test class. Any help would be much appreciated. Also, my code coverage is 75% on Trigger 3 if I take the "update" part out of my test class, but it's 0% when I add that piece back in. Any help would be much appreciated!

trigger Trigger2 on Opportunity (after update){  

    if(checkRecursive.runOnce())
    {     
        for(Opportunity opp  : Trigger.New)  
            {     
                //Trigger Action Logic  
                List<Account> accList = [Select Brand__c from Account where id =: opp.AccountId];
                for(Account acc : accList)  
                    {  
                        acc.Brand__c = opp.Subtype__c;  
                    }  
                update accList;       
            }  
       }     
    }

trigger Trigger3 on Account (after insert, after update)   
        {  

    if(checkRecursive.runOnce())
    {

            for(Account acc : Trigger.New)  
                {     
                    //Trigger Action Logic  
                    List<Opportunity> listOpp = [Select Subtype__c from Opportunity where AccountId =: acc.id];        
                    for(Opportunity opp : listOpp)  
                        {  
                            opp.Subtype__c = acc.Brand__c;  
                        }  
                    update listOpp;      

                }  
            }    
        }

@isTest public class TestOpportunityUpdate{

static testmethod void insertOpportunity() {

    Account a = new Account();
    a.Name = 'Mexico Villa Resort';
    a.Brand__c = 'InnVite';
    a.Lead_Source__c = 'AAHOA';
    a.Lead_source_info__c = 'test';
    a.Property_Segment__c = 'Unknown';
    a.Website = 'www.yahoo.com';

    insert a;

    Opportunity o1 = new Opportunity(AccountId = a.Id, Name = 'Test123', Subtype__c = 'Chain', StageName = 'Negotiation/Review', CloseDate = system.today());        

    insert o1;

// update the Opportunity SubType.
o1.Subtype__c = 'InnLink';
update( o1 );

//check to see if Opportunity field updated. 
 o1 =  [SELECT Id, Subtype__c FROM Opportunity
         WHERE Id = :o1.Id];

System.assertEquals('InnLink', o1.Subtype__c);

 //check to see if Account field updated. 
 a =  [SELECT Id, Brand__c FROM Account
         WHERE Id = :a.Id];

System.assertEquals('InnLink', a.Brand__c);

// update the Account SubType.
a.Brand__c = 'PMS';
update( a );

//check to see if Account field updated. 
 a =  [SELECT Id, Brand__c FROM Account
         WHERE Id = :a.Id];

System.assertEquals('PMS', a.Brand__c);           

//check to see if Opportunity field updated.
 o1 =  [SELECT Id, Subtype__c FROM Opportunity
         WHERE Id = :o1.Id];

System.assertEquals('PMS', o1.Subtype__c);        

    }

}

2 Answers 2

1

Welcome to the wonderful world of Apex! A couple of suggestions while we work through your issues:

  1. You are really going to want to take that SOQL query and the subsequent update out of the FOR loop.
  2. Is there a specific reason you're using "SeeAllData" ? Normally you want to avoid this.

Let me know if you'd like to discuss those further, but beginning with those will most definitely help clean up some of the overall execution, which can help us pinpoint the specific issue!

12
  • THANK YOU! That totally helped for Trigger 2, and makes sense not to need a FOR loop since there is only 1 account for each opportunity. That trigger now has 100% code coverage!
    – KPdev
    Sep 24, 2015 at 21:34
  • For trigger 3 though, don't I still need a FOR loop since there can be multiple opportunities for each account?
    – KPdev
    Sep 24, 2015 at 21:35
  • I removed the FOR loop for trigger 3, and it looks like this now: trigger Trigger3 on Account (after update) { if(checkRecursive.runOnce()) { for(Account acc : Trigger.New) { //Trigger Action Logic Opportunity o = [Select Subtype__c from Opportunity where AccountId =: acc.id]; o.Subtype__c = acc.Brand__c; update o; } } }
    – KPdev
    Sep 24, 2015 at 21:35
  • It works, but when I test it in my test class, I get that the expected result = PMS and actual result = InnLink.
    – KPdev
    Sep 24, 2015 at 21:37
  • Here's that portion of my test class: // update the Account SubType. a.Brand__c = 'PMS'; update( a ); //check to see if Account field updated. a = [SELECT Id, Brand__c FROM Account WHERE Id = :a.Id]; System.assertEquals('PMS', a.Brand__c); //check to see if Opportunity field updated. o1 = [SELECT Id, Subtype__c FROM Opportunity WHERE Id = :o1.Id]; System.assertEquals('PMS', o1.Subtype__c);
    – KPdev
    Sep 24, 2015 at 21:37
0

I would consider using the process builder to accomplish this task but along with Adam's suggestions I would also
3. Remove any DML statements from within your for loop.
4. Check the values to see if they don't match and only update those that don't already match
5. Is it necessary to run after an account is inserted, I'd imagine an opportunity wouldn't exist yet at this point and if there is an auto creation somewhere then I would default it to the brand value.
6. Consider the behavior on closed opportunities, would you want any record change to change the account field? And on the opposite end, do you want any account record change to update the closed opportunities?

5
  • Like this? trigger Trigger3 on Account (after update) { if(checkRecursive.runOnce()) { List<Opportunity> listOpp = [Select Id, Subtype__c, AccountId from Opportunity where AccountId in :trigger.newMap.keySet()]; for(Opportunity opp : listOpp) { opp.Subtype__c = trigger.newMap.get(opp.AccountId).Brand__c; } update listOpp; } }
    – KPdev
    Sep 24, 2015 at 22:12
  • Sorry, wrong comment window!
    – KPdev
    Sep 24, 2015 at 22:13
  • Thank you for answering me! I've removed Account insert, because you're right, the opp would not be created yet. And I hadn't thought about #4 and #6, so I will take those into consideration!
    – KPdev
    Sep 24, 2015 at 22:15
  • I need to get better at the process builder - since it's a picklist, I couldn't figure out how to get my field to update. My choices are "select prior choice, select latter choice, select a specific value" ~ or something like that! :-(
    – KPdev
    Sep 24, 2015 at 22:16
  • @KPdev in the process builder you should be able to select the opportunity field and then for type select reference and then for value select the other picklist field. I believe in workflow rules you are limited to the choices you mentioned.
    – Jenny B
    Oct 1, 2015 at 19:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .