How to populate formula fields without inserting/updating a record in Salesforce Apex

Formula fields are read-only fields that are defined by a calculated expression. It’s the most similar thing of an Excel formula that you can find in Salesforce and it doesn’t require strong knowledge to set one. As a read-only field, you cannot assign values to it. That should not be an issue in most of the times, but it could cause you problems when you want to test an apex piece of code.

Imagine a situation where you have an if condition that checks the value of a formula field. You will need at some point to perform a DML so the formula field populates and you can continue with your test. However, inserting or updating records in apex tests could be time consuming depending on the situation. Also, if your test is a Unit Test, you won’t want to pass through the trigger of the object. Remember that unit tests should be as isolated as possible.

Code examples

This is the error you will find if you try to update a formula field:

MyObject__c obj = new MyObject__c();
obj.MyFormula__c = 'test';

ERROR -> Field is not writeable: MyObject__c.MyFormula__c

If you want to populate the value in a formula field avoiding DMLs, you could use the Formula Class to force Salesforce evaluate the field:

MyObject__c obj = new MyObject__c();
// assign values to other fields if your formula needs them
Formula.recalculateFormulas(new List<MyObject__c> { obj });

System.assertNotEquals(null, obj.MyFormula__c); // true :)

If you want to know more about the potential errors you can find, you can refer to the returned object: List<FormulaRecalcResult>

MyObject__c obj = new MyObject__c();
// assign values to other fields if your formula needs them
List<FormulaRecalcResult> results = Formula.recalculateFormulas(new List<MyObject__c> { obj });

// isSucess(): boolean that will confirm that the record was updated succesfully
System.assert(results[0].isSuccess()); 

// getSObject(): return the updated sObject (the original obj will be updated as well))
MyObject__c sameRecord = (MyObject__c) results[0].getSObject(); 

List<FormulaRecalcFieldError> errors = results[0].getErrors();
errors[0].getFieldName(); // field that failed 
errors[0].getFieldError(); // error description

Formula.recalculateFormulas method

List<System.FormulaRecalcResult> Formula.recalculateFormulas(List<sObject> objs): It’s the only static method from Formula class and it updates ALL formula fields from the sObject present in the list. If you have to assign other fields in order to evaluate the formula field, Salesforce will load that data and this will affect the governor limits. Also, this will work even if you queried those sObjects from a SOQL.

So, to wrap up, these are advantages of using recalculateFormulas method:

  • Avoid performing DMLs and SOQL that slow your test runs and run against your governor limits.
  • Isolate unit tests from other classes/triggers so there are no dependencies.

If you need more info, check the Apex Reference Guide.

Leave a Comment