0

As Daniel Appleman, has noted in his book "Advanced Apex", it is important to design triggers so to be smart with respect to recursion and re-entrancy. Take the following requirement that mirror our use case:

Ensure a new CustomObject1 has a lookup towards Account set to the Account whose Field2 (ExternalId) is equal to CustomObject1.Field1. If such an Account does not exist, create it. Such a lookup is required.

Because the lookup is required, we implementd a beforeInsert/beforeUpdate trigger using a static Set, which we would use to store the value of Field1 that we already processed so that subsequent trigger executions would not perform the same work of creating account if it doesn't exist.

However, we notice that this was leading to test failures because, in our tests, we insert two different CustomObjects having the same Field1 value with two separate DML statements, which is a single transaction.

Because your objects have no id yet, you can't use them to determine if you have already processed them. You need to a static Map, whose key is either the System.hashCode of your CustomObject or if you are lucky, an ExternalId on CustomObject. What is the most appropriate solution to this problem?

  • 1
    FYI it would be easier to provide you with a solid, detailed answer, if you include clear, specific details about your exact use case and what you are trying to accomplish. – Adrian Larson May 16 at 10:36
  • I'm going to wait until you update your post with an example to show you what I mean, because without that anything I write is just a guess. – Adrian Larson May 16 at 12:37
2

There are two common and appropriate techniques: use of @TestSetup, and use of Test.startTest()/Test.stopTest(). Note that the former clears all static flags but does not reset limits, while the opposite is true on both counts for the latter.

  • I opened this issue because Test.startTest / Test.stopTest are not resetting the statics but just the limits – Edmondo1984 May 16 at 10:30
  • 1
    You're going to have to reset manually. I can add some more detail shortly. – Adrian Larson May 16 at 10:31
  • Thanks, your push to write a more precise question made us investigate further the problem and we found out that there is an issue in the way our triggers idempotency was designed. What was happening is that we have never considered the opportunity that the trigger might be entered twice but not due to re-entrancy, simply due to two separate DML statements in the same execution context. – Edmondo1984 May 16 at 14:17
  • I find that is often the case. Writing questions well ends up resolving 25-50% of problems for me. – Adrian Larson May 16 at 14:30
  • Any thoughts on how you could keep track of the elements processed if you haven't got a mandatory external lookups? – Edmondo1984 May 16 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.