3

Question

Are there any best practices out there for testing apex code that is driven by formula fields so that changes to the formula field formula don't break your test?

Background

Good test methods shouldn't break when administrators make changes. While impossible, it's nice to get as close as possible to this ideal.

Formula fields make this tricky. In order to get a predictable (deterministic) result from your test you often need to ensure the formula field has a particular value.

One option is to have your test to "know" the formula field syntax, and setup the data to ensure you get a desired value in the formula field. Downside is now whenever that formula field changes, you're test breaks.

Another option is a Test.isRunningTest() switch in your code that alters the logic code to bend around the formula. Downside is it's easy to write a test that gives you an all clear, but is broken for end user.

Neither of these is great, has anyone out there run into this and found something that works for them?

Practical Example

This obviously won't matter in a lot of cases, since formula fields don't really change much, but to give it some context, imagine the following scenario loosely based on a project I'm working on.

You've got a trigger that creates a project assignment record based on changes to a parent project record that lists who is on a project, for how long, and what their roles are. The project assignment has an end date field you need to populate. The logic to determine the end date is complicated, i.e. (if project end date is null, then project start date + 20, unless progress is greater than 50%, in which case it's project start date + 10), and the requestor expects there going to need to tweak it several times to get the end date right. So you create formula field, "Project Assignment End Date" to encapsulate the logic, and your trigger just looks at the formula field, doesn't have to worry about what the logic is, and the requestor can make changes without calling the developer in. It's working great, but now you need to write your test methods. How do you go about it so you have a test method that truly tests your code, but doesn't break the first time an admin makes a change?

An even better example would be using a formula field as configuration to drive code, in which case it becomes a must tests can't break on changes, and important that you can test that some version of the formula works.

6
  • 2
    It kind of depends on the circumstances, obviously. But when I have run into cases where I needed to ensure a complicated formula had a specific value, I would write a dedicated test utility method to that end.
    – Adrian Larson
    Jun 10, 2015 at 18:40
  • @AdrianLarson so idea being similar to test utils for the usual data creation, if a validation rule is created or the formula changes, your tests still break, you just ensure you only have one place to make a change? Jun 10, 2015 at 18:42
  • Exactly. We wrote a generic SObjectFactory utility that can create any object type and you just specify field/value pairs, but this sort of functionality forces us to diverge from that paradigm. The general TestUtils paradigm I've seen might require less of a shift.
    – Adrian Larson
    Jun 10, 2015 at 18:47
  • Ralph -- by extension, your question also applies to assignment rules, workflows, processes, validation rules - complex examples of the aforementioned might benefit from regression tests to catch inadvertent clicks-not-code admin changes
    – cropredy
    Jun 10, 2015 at 22:30
  • If you've got apex behavior that is driven by the known-good behavior of a formula field's output, your unit tests should verify that it is behaving properly via an independent test. By extension, do you also need to verify that this formula field is outputting proper data at run time? i.e. once this formula field is in prod, how do you verify that the field remains trustworthy? (outside of strict change management processes, that is.)
    – Mark Pond
    Jun 16, 2015 at 18:30

3 Answers 3

4

First, thank you, Ralph, for asking this question and putting yourself out there. As a matter of communication I don't mean to call you out on anything at all, but I want to give a detailed, (hopefully) thoughtful answer to a detailed, thoughtful question.

Are there any best practices out there for testing apex code that is driven by formula fields so that changes to the formula field formula don't break your test?

As someone who'd asked the same question myself, I think I understand why you posted to Stack Exchange. However, I believe a better question is, "How can I make sure critical formula fields are tested properly to protect against unintended consequences?"

I believe you should want changes to formula fields to break Apex tests, especially when your app logic depends on those formula fields. Imagine having an Apex class to create the output that the formula field currently produces. In that case you're forced to write an Apex test for that other class, and in the app logic that you are writing you would rely on proper test coverage of the other class.

A formula field is simply another means of automating business logic. And just like other means, such as Apex, Visual Workflow, JavaScript, workflow rules or Process Builder, a formula field used as a critical automation component should have adequate test coverage.

So, regarding this idea:

Good test methods shouldn't break when administrators make changes.

I believe that good test methods should break when administrators (or developers) make changes that impact the app logic that you've implemented. I think this is the only way to sustainably work in a team environment with multiple admins and devs.

Recommendations

All that to say I support both recommendations from NSjonas and Bobby White.

... treat the Formula Field as though it were a stand alone class and ensure that you have adequate code coverage for all of the branches that are implicit in it.

-- Bobby White

I would recommend de-coupling the class with the actual instance of the object if possible. That way you can test the branch conditions individually by passing whatever value you want into the code.

-- NSjonas

3
  • 1
    I get where you're coming from, but we're balancing ease of configuration versus testing, if the end result of the formula is a simple date, it's relative trivial to ensure the code that uses the formula field works with a set of test dates, what's challenging is if the input comes from a formula field of complex logic, there isn't a great way to control what date value you're getting for a test. My case applies to where formula is configuration, if the configuration is changed, the test still works, so I would disagree Jun 16, 2015 at 19:23
  • ooops, hit enter early, in summary i'd disagree that formula fields in all cases should cause test methods to fail if they're changed, the test should only fail if you're DEPENDING on that formula field providing a particular value. Finally, their is a big assumption in your answer, that the client has easy access to developers. If they don't a failing tests means any change set they deploy fails, and all development grinds to a halt until it's addressed. And of course, no need to apologize for "calling me out", the whole point is this discourse right here, I Jun 16, 2015 at 19:26
  • one last corollary, good test methods should break if an administrator breaks something that breaks the behavior of the code, good test methods should NOT break if an administrator changes something that doesn't break the function of the code, in otherwords, automated tested should mirror what would be done by an end user, if it still works for the end user and the test fails, that's not a worthwhile test since you'll spend all your time updating it even when it's working Jun 16, 2015 at 19:30
2

My recommendation is to treat the Formula Field as though it were a stand alone class and ensure that you have adequate code coverage for all of the branches that are implicit in it.

For example, if you've added a Formula Field to 'MyObject' called 'Derived' IF(condition1, expression1, expression2)

Assuming that expression1 and two were simple, you'd need two Unit test cases: Condition1 = true Condition1 = false

You can keep the data setup "local" to the Unit tests in the simplest case.

If Expression1 (or 2) is inherently more complex, then you'll want to separate out the setup to an external class.

2

You basically need to assert that the result of the test follows the correct logic based on the value in the formula. Since by design the formula is meant to be changed, you should not be making any assertions on what the formula output is given any input (black box).

If you code has branch conditions based on this formula value that need to be tested, then I would recommend de-coupling the class with the actual instance of the object if possible.

That way you can test the branch conditions individually by passing whatever value you want into the code. Your end-to-end test would need to leave out any asserts specific to what branch is taken.

1
  • BTW: I was totally wrong about being able to set the formula field. Throws a read only exception (you probably already knew this)
    – NSjonas
    Jun 10, 2015 at 21:52

You must log in to answer this question.

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