[SalesForce] Apex Test not updating parent object field based on child object formula fields

I have a before insert, before update trigger that updates a value in a parent object when a new child object is inserted or updated. The child object contains loads of checkboxes which are used by other formula fields in this object to output a total value to a final formula field. Once the child object is saved, the parent object value is updated with the child's calculated total value.

This works as expected via the UI, but when testing, the parent object retains its initial value for this field. ("1", as per test below)
In the initial tests, the formula values in the child object were not updating based on the selected checkbox values, but I added a second query to get the inserted child object and can now see that its formula fields are updating.

The value for the parent is still not updating through the test class, however.

In desperation, I added a query for the Parent object as well, but this isn't helping and the value for the parent is still the same as at the start.

EDIT:

I've updated the question to correct the > vs < symbol (it was a typo in the paste) and to clarify my comments.
The formula fields that calculate the values associated with the various checkboxes in the
child object work and we've tested this by adding numerous child objects via the GUI. I've added comments to the test class to illustrate what the values are when testing.
What happens is:

  • User creates new child object, selecting a number of optional checkboxes.
  • Upon save, formula fields on the child object calculate which checkboxes are checked, and associate weighted values to them.
  • The output for these fields is totalled by a final formula field, giving the final score for this object.
  • This final score is then added to the parent object.

The above works as it should in live. The issue isn't with the calculation of the scores, but rather with the fact that, in my test class only only, they aren't written to the parent object.

Code below:

Trigger:

trigger updateParent on ChildObject (before insert, before update) {
  List cobj = new List();
  List parentIDs = new List();
  for(Integer i = 0; i < Trigger.new.size(); i++) 
  { 
     cobj.add(Trigger.new[i]);
     parentIDs.add(Trigger.new[i].ParentID__c);
  }  
  Map pObList = new Map([SELECT Id,Name,value FROM Parent_Obj WHERE Id in:parentIDs]);
  String outval = '';
  for(ChildObject r : cobj)
  {
    if(pObList.containsKey(r.ParentID__c))
    {
      //Change decimal to string
      outval = r.Calculated_Risk__c.format();
      pObList.get(r.ParentID__c).value = outval;
    }
  } 
  update pObList.values();
}

Test Class

private class updateParentTest {

    static testMethod void testNewChildObj() {

        Parent_Obj parent = new Parent_Obj(name='Test Parent_Obj', Account = testAccount, 
                                     value = '1'); //testAccount insert removed for clarity.
        insert parent;
        //The debug message below correctly shows that the parent value is == 1
        //as it was inserted above
        system.debug('***START Parent Obj Value: ' + parent.value);

        //The formula fields calculate a final value depending on whether or not
        //loads of checkboxes are selected. The below is a simplification, but the 
        //formulas themselves work. The below value should == 2.2 as a final value
        Child_Object child = new ChildObject(Parent_Obj__c = parent.Id, checkbox1 = true,
                                    checkbox2 = true, checkbox3 = true, checkbox4 = true);
        insert child; 

        //Query child object to update formula fields
        //Before I added this query, system.debug messages showed null for the formula
        //fields in the child object. Now they correctly show the calculated value for each component, and the
        //finalformulavalue field shows the correctly calculates value of 2.2 
        //(as per the test fields checked above)
        Child_Object qrychild = [SELECT Id,Parent_Obj__c,checkbox1,checkbox2,checkbox3,
                                        checkbox4,formula1,formula2, formula3, 
                                        finalformulavalue, Parent_Obj__r.id,  
                                        Parent_Obj__r.value 
                                   FROM Child_Object WHERE Id =: child.Id];

        //Query the parent object. Hoping that this would update the value.
        Parent_Obj parent = [SELECT id,name,value FROM Parent_Obj WHERE Id =: parent.Id];

        //I replaced an assertion here with the debug below so I could see what the
        //parent value was ultimately set at. The assertion was for the final 
        //value of 2.2, 
        //which is correct according to how the formula works out, and my experience
        //from testing this via the GUI interface. (i.e.: If I create the child object, 
        //select the checkboxes as per the test and save, not only does the 
        //child object formula appear correctly, but this value is also updated on the 
        //parent. 
        system.debug('***END Parent Obj Value: ' + parent.value); // == 1, should be 2.2

    }

}

So…
It works as expected from the UI, but not in my test class. Does anyone have any ideas?

Best Answer

As OP indicated my comment was the solution, I'm converting to an answer ..

1) Your trigger on ChildObject updates the Parent__c during a before trigger event -- best practice is to update related objects in after triggers;

2) r.Calculated_Risk__c won't have a value in a before insert trigger - see https://salesforce.stackexchange.com/questions/9147/formula-fields-and-triggersalesforce.stackexchange.com/questions/9147/

Hence - use an after, not a before trigger in this use case

Related Topic