6

I have observed that in some orgs, some Apex tests will fail if those tests run in parallel with other tests, but will pass if the same tests do not run in parallel. I tried to find information from Salesforce that describes in detail what information/context is shared between Apex tests and all I could find is this:

Sometimes, parallel test execution results in data contention issues, and you can turn off parallel execution in those cases. In particular, data contention issues and UNABLE_TO_LOCK_ROW errors might occur in the following cases.

Can someone explain what data/context is shared between individual tests when executed in parallel?

3 Answers 3

7

Salesforce is supposed to ensure that each test's environment is isolated from all others. However, there are definitely cases where there is a bit of leakage in the persistence layer (i.e. the Salesforce database).

In my experience this happens almost entirely around Custom Settings.

To resolve this we re-engineered our code to avoid ever storing custom settings records during test execution. Instead, we have a class that can be asked for the relevant settings which caches the returned record as an in-memory singleton. Further, when tests are running the record to be returned is constructed without fetching it from the database so we have a guaranteed default state. Thus, if the test fetches the settings record through this class, it can modify it as needed. The production code under test uses this same class and therefore receives that same custom settings record.

There could be some other leakage cases which I'm sure will be added as further answers.

1
  • 1
    That would be the textbook example most of us have run into.
    – Adrian Larson
    May 27, 2021 at 16:11
6

The problem is with things that can be accessed at the same time by more than one process/transaction. That won't be in-memory data - Apex variables - because only a single thread ever runs. But it can be any resource shared by more than one process/transaction which normally means rows in the database.

As Phil has mentioned, custom settings are one example: values that are persisted in the database and shared by all processes/transactions. So if your tests update the settings to test a specific combination of settings, simultaneous updates are possible when running tests in parallel, and if the locks are held for too long errors result.

Another case we have seen is tests that created Contact records but defaulted those records to a default Account. The locking of records happens at the root object of the master-detail tree, so with multiple Contacts being manipulated by the tests running in parallel, but only one Account where the lock was being applied, we had the locking error problem. Those tests have now been changed to create an independent Account for each Contact.

3

Salesforce basically has two lock domains, "production" and "unit test." You can lock a record in production, and the same record in test, but you cannot lock the same record in two different transactions of production or test simultaneously. For many usual test situations, this doesn't matter, but if you have anything involving a unique index (e.g. custom settings), you'd best be sure you're locking records serially, and not trying to update or lock those records in parallel.

The most obvious cause is Custom Settings, especially org-wide default settings in the hierarchy model, but this can also be, for example, an Account with a unique indexed field. You will never need to worry about CANNOT_LOCK_ROW during a deployment, because those tests always run in serial mode, but you may "randomly" get errors when running tests in parallel.

The two solutions are to either (a) make randomly unique values in your unit tests, or (b) use isParallel=false to disable parallel testing for problematic tests (you can choose to have some run in parallel for efficiency, and isolate problematic tests in serial mode).

1

You must log in to answer this question.

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