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
Peter BölkePeter Bölke 

How to test a Roll-Up Trigger

Hello,

i have a problem testing my Roll-Up Trigger. Here it is:
 
@isTest(SeeAllData=true)
public class TrgTractorFleetSizeRollupTest {
    static testmethod void validateUploadNewAccount(){
        Account a1 = new Account(Name = 'A1');
        insert a1;
        Account a1a1 = new Account(Name = 'A1A1', ParentId = a1.id);
        insert a1a1;
        Account a1a1a1 = new Account(Name = 'A1A1A1', ParentId = a1a1.id, SoldUnits__c = 125);
        insert a1a1a1;
        Account a1a1a2 = new Account(Name = 'A1A1A2', ParentId = a1a1.id, SoldUnits__c = 125);
        insert a1a1a2;
        System.debug([SELECT Id, SoldUnits__c from Account Where Name = 'A1A1'][0]);
        Account a1a2 = new Account(Name = 'A1A2', ParentId = a1.id);
        insert a1a2;
        Account a1a2a1 = new Account(Name = 'A1A2A1', ParentId = a1a2.id, SoldUnits__c = 100);
        insert a1a2a1;
        Account a1a2a2 = new Account(Name = 'A1A2A2', ParentId = a1a2.id, SoldUnits__c = 90);
        insert a1a2a2;
        System.debug([SELECT Id, SoldUnits__c from Account Where Name = 'A1A2'][0]);
        System.debug(a1a2.SoldUnits__c);
        System.assertEquals([SELECT Id, SoldUnits__c from Account Where Name = 'ss'][0].SoldUnits__c, 450);
    }
}

It doesnt update the value SoldUnits__c  at Account 'A1' which is the grandparent Account.
Any Idea?

Thanks
Peter
Best Answer chosen by Peter Bölke
Paul S.Paul S.
Peter - I was able to get this alternate version of your trigger to work in a dev sandbox.  Give it a try and let me know if it accomplishes what you were looking for.  You may need to make sure it also covers the functionality of lines 44 - 68, above, but I believe it does.  
trigger TrgSoldUnitsRollup on Account (after insert, after update) {

    Set<Id> setOfParentAccountIds = new Set<Id>();
    
    for(Account a : trigger.New)
    {
        if((a.SoldUnits__c != null || a.RevenueUnits__c != null) && a.Status__c == 'Active')
        {
            setOfParentAccountIds.add(a.ParentId);
        }
    }
    
    List<Account> accountsToUpdate = new List<Account>();
    
    for(Account a : [SELECT Id, SoldUnits__c, RevenueUnits__c, (SELECT Id, SoldUnits__c, RevenueUnits__c FROM ChildAccounts) FROM Account WHERE Id IN : setOfParentAccountIds])
    {
        Decimal soldUnits = 0;
        Decimal revenueUnits = 0;
        
        for(Account aChild : a.ChildAccounts)
        {
            if(aChild.SoldUnits__c != null){
                soldUnits += aChild.SoldUnits__c;
            }
            if(aChild.RevenueUnits__c != null){
                revenueUnits += aChild.RevenueUnits__c;
            }
        }
        
        a.SoldUnits__c = soldUnits;
        a.RevenueUnits__c = revenueUnits;
        
        accountsToUpdate.add(a);
        
    }
    
    update accountsToUpdate;
}
I also had to slightly reorder the operations of your test class:
@isTest(SeeAllData=true)
public class TrgTractorFleetSizeRollupTest {
    static testmethod void validateUploadNewAccount(){
		List<Account> la1 = new List<Account>();
        List<Account> la2 = new List<Account>();
		Account a1 = new Account(Name = 'A1', Status__c = 'Active');
		insert a1;
        
        Account a1a1 = new Account(Name = 'A1A1', ParentId = a1.id, Status__c = 'Active' );
        Account a1a2 = new Account(Name = 'A1A2', ParentId = a1.id, Status__c = 'Active');
        la1.add(a1a1);
        la1.add(a1a2);
        insert la1;
        
        Account a1a1a1 = new Account(Name = 'A1A1A1', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a1a2 = new Account(Name = 'A1A1A2', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a2a1 = new Account(Name = 'A1A2A1', ParentId = a1a2.id, SoldUnits__c = 100, Status__c = 'Active');
        Account a1a2a2 = new Account(Name = 'A1A2A2', ParentId = a1a2.id, SoldUnits__c = 90, Status__c = 'Active');
        la2.add(a1a1a1);
        la2.add(a1a1a2);
        la2.add(a1a2a1);
        la2.add(a1a2a2); 
        insert la2;
        
        Account a = [SELECT Id, SoldUnits__c from Account Where Name = 'A1' LIMIT 1];
        system.debug(a);
        System.assertEquals(440,a.SoldUnits__c);
    }
}

All Answers

Paul S.Paul S.
Peter - can you post the trigger code please?
Peter BölkePeter Bölke
Hello Paul,

here is my Trigger... 
 
trigger TrgSoldUnitsRollup on Account (after insert, after update) {
    
    Boolean isLastChild = ([SELECT COUNT() FROM Account Where ParentId=:Trigger.New[0].Id] == 0);
    AggregateResult sumRevenues = [SELECT SUM(RevenueUnits__c) Revenues, SUM(SoldUnits__c) Sold FROM Account Where ParentId=:Trigger.New[0].Id];
    ClsSoldFleetSizeRollupHelper th = new ClsSoldFleetSizeRollupHelper();
    
    if(isLastChild == false && (Trigger.New[0].SoldUnits__c != sumRevenues.get('Sold') || Trigger.New[0].RevenueUnits__c != sumRevenues.get('Revenues'))){
        
        System.debug('1');
        if(Trigger.New[0].SoldUnits__c != sumRevenues.get('Sold')){
            Trigger.New[0].SoldUnits__c.AddError('Solds unit of this Account must be equal to sum of its Subaccounts. Calculated Sum of Sold: '+ sumRevenues.get('Sold'));
        }
        if(Trigger.New[0].RevenueUnits__c != sumRevenues.get('Revenues')){
            Trigger.New[0].RevenueUnits__c.AddError('Revenue of this Account must be equal to sum of its Subaccounts. Calculated Sum of Revenues: '+ sumRevenues.get('Revenues'));
        }
    }
        if(((Trigger.New[0].SoldUnits__c != null) || Trigger.New[0].RevenueUnits__c != null) && Trigger.New[0].Status__c == 'Active') {
            System.debug('2');
            if (Trigger.New[0].ParentID != null){
                Account acc = [Select Id, Name, ParentId, SoldUnits__c, RevenueUnits__c from ACCOUNT Where Id = :Trigger.New[0].Id];
                Double unitSells = Trigger.New[0].SoldUnits__c;
                Double revenueSells = Trigger.New[0].RevenueUnits__c;
                List<Account> getSameChilds =  [Select Id, Name, ParentId, SoldUnits__c, RevenueUnits__c from ACCOUNT Where ParentId=:acc.ParentID];
                for(Account a : getSameChilds){
                    if(a.Id != acc.Id){
                        System.debug(a.Name + ' ' + a.ParentId);
                        if(a.SoldUnits__c != null){
                            unitSells = unitSells + a.SoldUnits__c;
                        }
                        if(a.RevenueUnits__c != null){
                            revenueSells = revenueSells + a.RevenueUnits__c;
                        }
                    }
                }
                
                Account parent = [Select Id, SoldUnits__c, RevenueUnits__c from ACCOUNT Where Id = :acc.ParentID][0];
                parent.SoldUnits__c = unitSells;
                parent.RevenueUnits__c = revenueSells;
                update parent;
                
            }             
        }
    
    else if(isLastChild == false && Trigger.New[0].ParentID != null&& (Trigger.New[0].SoldUnits__c != sumRevenues.get('Sold') || Trigger.New[0].RevenueUnits__c != sumRevenues.get('Revenues'))){
        String idcurrent = Trigger.New[0].ParentID;
        System.debug('3');
        //while([Select Id, Name, ParentId, SoldUnits__c, RevenueUnits__c from ACCOUNT Where Id = :idcurrent].ParentId != null){
            Account parent = [Select Id, Name, ParentId, SoldUnits__c from ACCOUNT Where Id = :idcurrent];
            AggregateResult getChilds =  [Select SUM(RevenueUnits__c) Revenues, SUM(SoldUnits__c) Sold from ACCOUNT Where ParentId=:Trigger.New[0].ParentId];
            //idcurrent = [Select Id, Name, ParentId, SoldUnits__c from ACCOUNT Where Id = :idcurrent].ParentId;
            parent.SoldUnits__c = Integer.valueOf(sumRevenues.get('Solds'));
            parent.RevenueUnits__c = Integer.valueOf(sumRevenues.get('Revenues'));
            update parent;
        //}
        
    }else if(isLastChild == false && (Trigger.New[0].SoldUnits__c != sumRevenues.get('Sold') || Trigger.New[0].RevenueUnits__c != sumRevenues.get('Revenues'))){
        String idcurrent = Trigger.New[0].ParentID;
        Account parent = [Select Id, Name, ParentId, SoldUnits__c from ACCOUNT Where Id = :idcurrent];
        AggregateResult getChilds =  [Select SUM(RevenueUnits__c) Revenues, SUM(SoldUnits__c) Sold from ACCOUNT Where ParentId=:Trigger.New[0].ParentId];
        if(Trigger.New[0].SoldUnits__c != sumRevenues.get('Solds')){
            parent.SoldUnits__c = Integer.valueOf(sumRevenues.get('Solds'));
            //Trigger.New[0].SoldUnits__c.AddError('Sold fleet size of this Account must be equal to sum of its Subaccounts. Calculated Sum of Sold: '+ sumRevenues.get('Sold'));
        }
        if(Trigger.New[0].RevenueUnits__c != sumRevenues.get('Revenues')){
            parent.RevenueUnits__c = Integer.valueOf(sumRevenues.get('Revenues'));
            //Trigger.New[0].RevenueUnits__c.AddError('Revenue fleet size of this Account must be equal to sum of its Subaccounts. Calculated Sum of Revenues: '+ sumRevenues.get('Revenues'));
        }
    }
    
}
Thanks in advance for any advise
Paul S.Paul S.
Thanks.  Are you getting an error and/or assertion failure?  One thing I see quickly is that your assertion is querying for an account record named "ss" (line 21 of your test class, above), but you don't seem to have an account record with that name.
Peter BölkePeter Bölke
Hello Paul,

the account you mentioned is one which exist. I tried tthe test there but without success.
Paul S.Paul S.
Peter - one more thing...line 17 of your trigger requires that the account status be active, but that's not explicitly stated/set in your test class.  Unless that's set using a default value, I'd try that.
Peter BölkePeter Bölke
Thanks that gave me step ahead, but i got this message "System.LimitException: Too many SOQL queries: 101"

I changed the code in this way
@isTest(SeeAllData=true)
public class TrgTractorFleetSizeRollupTest {
    static testmethod void validateUploadNewAccount(){
        List<Account> la = new List<Account>();
        Account a1 = new Account(Name = 'A1', Status__c = 'Active');
        Account a1a1 = new Account(Name = 'A1A1', ParentId = a1.id, Status__c = 'Active' );
        Account a1a1a1 = new Account(Name = 'A1A1A1', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a1a2 = new Account(Name = 'A1A1A2', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a2 = new Account(Name = 'A1A2', ParentId = a1.id, Status__c = 'Active');
        Account a1a2a1 = new Account(Name = 'A1A2A1', ParentId = a1a2.id, SoldUnits__c = 100, Status__c = 'Active');
        Account a1a2a2 = new Account(Name = 'A1A2A2', ParentId = a1a2.id, SoldUnits__c = 90, Status__c = 'Active');
        la.add(a1);
        la.add(a2);
        la.add(a1a1);
        la.add(a1a2);
        la.add(a1a1a1);
        la.add(a1a1a2);
        la.add(a1a2a1);
        la.add(a1a2a2); 
        insert la;
        System.assertEquals([SELECT Id, SoldUnits__c from Account Where Name = 'A1'][0].SoldUnits__c, 450);
    }
}



But his give me another error 'insert la;' : "System.DmlException: Insert failed. First exception on row 4 with id 0013E00000XRoKhQAL; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id]"
Peter BölkePeter Bölke
i tried another thing 
 
@isTest(SeeAllData=true)
public class TrgTractorFleetSizeRollupTest {
    static testmethod void validateUploadNewAccount(){
		List<Account> la1 = new List<Account>();
        List<Account> la2 = new List<Account>();
		Account a1 = new Account(Name = 'A1', Status__c = 'Active');
		insert a1;
        Account a1a1 = new Account(Name = 'A1A1', ParentId = a1.id, Status__c = 'Active' );
        Account a1a1a1 = new Account(Name = 'A1A1A1', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a1a2 = new Account(Name = 'A1A1A2', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a2 = new Account(Name = 'A1A2', ParentId = a1.id, Status__c = 'Active');
        Account a1a2a1 = new Account(Name = 'A1A2A1', ParentId = a1a2.id, SoldUnits__c = 100, Status__c = 'Active');
        Account a1a2a2 = new Account(Name = 'A1A2A2', ParentId = a1a2.id, SoldUnits__c = 90, Status__c = 'Active');
        la1.add(a1a1);
        la1.add(a1a2);
        la2.add(a1a1a1);
        la2.add(a1a1a2);
        la2.add(a1a2a1);
        la2.add(a1a2a2); 
        insert la1;
        insert la2;		
        System.assertEquals([SELECT Id, SoldUnits__c from Account Where Name = 'A1'][0].SoldUnits__c, 450);
    }
}

But endend up with: "System.AssertException: Assertion Failed: Expected: null, Actual: 450​"
Paul S.Paul S.
Peter - I was able to get this alternate version of your trigger to work in a dev sandbox.  Give it a try and let me know if it accomplishes what you were looking for.  You may need to make sure it also covers the functionality of lines 44 - 68, above, but I believe it does.  
trigger TrgSoldUnitsRollup on Account (after insert, after update) {

    Set<Id> setOfParentAccountIds = new Set<Id>();
    
    for(Account a : trigger.New)
    {
        if((a.SoldUnits__c != null || a.RevenueUnits__c != null) && a.Status__c == 'Active')
        {
            setOfParentAccountIds.add(a.ParentId);
        }
    }
    
    List<Account> accountsToUpdate = new List<Account>();
    
    for(Account a : [SELECT Id, SoldUnits__c, RevenueUnits__c, (SELECT Id, SoldUnits__c, RevenueUnits__c FROM ChildAccounts) FROM Account WHERE Id IN : setOfParentAccountIds])
    {
        Decimal soldUnits = 0;
        Decimal revenueUnits = 0;
        
        for(Account aChild : a.ChildAccounts)
        {
            if(aChild.SoldUnits__c != null){
                soldUnits += aChild.SoldUnits__c;
            }
            if(aChild.RevenueUnits__c != null){
                revenueUnits += aChild.RevenueUnits__c;
            }
        }
        
        a.SoldUnits__c = soldUnits;
        a.RevenueUnits__c = revenueUnits;
        
        accountsToUpdate.add(a);
        
    }
    
    update accountsToUpdate;
}
I also had to slightly reorder the operations of your test class:
@isTest(SeeAllData=true)
public class TrgTractorFleetSizeRollupTest {
    static testmethod void validateUploadNewAccount(){
		List<Account> la1 = new List<Account>();
        List<Account> la2 = new List<Account>();
		Account a1 = new Account(Name = 'A1', Status__c = 'Active');
		insert a1;
        
        Account a1a1 = new Account(Name = 'A1A1', ParentId = a1.id, Status__c = 'Active' );
        Account a1a2 = new Account(Name = 'A1A2', ParentId = a1.id, Status__c = 'Active');
        la1.add(a1a1);
        la1.add(a1a2);
        insert la1;
        
        Account a1a1a1 = new Account(Name = 'A1A1A1', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a1a2 = new Account(Name = 'A1A1A2', ParentId = a1a1.id, SoldUnits__c = 125, Status__c = 'Active');
        Account a1a2a1 = new Account(Name = 'A1A2A1', ParentId = a1a2.id, SoldUnits__c = 100, Status__c = 'Active');
        Account a1a2a2 = new Account(Name = 'A1A2A2', ParentId = a1a2.id, SoldUnits__c = 90, Status__c = 'Active');
        la2.add(a1a1a1);
        la2.add(a1a1a2);
        la2.add(a1a2a1);
        la2.add(a1a2a2); 
        insert la2;
        
        Account a = [SELECT Id, SoldUnits__c from Account Where Name = 'A1' LIMIT 1];
        system.debug(a);
        System.assertEquals(440,a.SoldUnits__c);
    }
}
This was selected as the best answer
Peter BölkePeter Bölke
Thanks very much. Its works perfectly
Paul S.Paul S.
Sure thing. One other thing - one assumption the code makes is that the parent account itself won't be selling any units. So, for example: Account C1: 10 units Account C2: 5 units If both of those were related to an account P1, the roll up on P1 would show 15. If, however P1 itself sold 10 units, the code currently isn't set-up to include that such that P1's unit sold field would show 25 units - it would still read 15.
Peter BölkePeter Bölke
Hello Paul,

thats ok. Only the "lowest" Elements in this Hierarchy should have manually entered values.