Andrew Hanna

Andrew Hanna

How to Run Apex Tests in Parallel Without Flaky Failures

How to Run Apex Tests in Parallel Without Flaky Failures

To run Apex tests in parallel without flaky failures, make every test create its own data, never write to records that exist outside the test, and generate unique values for fields like usernames. Then diagnose any remaining flake by rerunning that class on its own: if it passes alone and fails in parallel, you have an isolation problem, not a bug. Turning off parallel testing org-wide hides the symptom and slows every run.

Why do Apex tests fail only when they run in parallel?

By default, Salesforce runs asynchronous test classes concurrently, so two tests can compete for the same resource at the same moment. The failures cluster into three causes:

  • Record lock contention. A transaction waiting on a locked record gets 10 seconds before Salesforce returns UNABLE_TO_LOCK_ROW, and that limit cannot be changed, as Xappex explains. Parent records are locked silently when master-detail children are updated, when roll-up summaries recalculate and during sharing processing.
  • Org-wide unique values. Usernames are unique across Salesforce, so two classes inserting [email protected] at once fail with DUPLICATE_USERNAME, a pattern Salesforce Central documents.
  • Shared org data. A test using @isTest(SeeAllData=true) reads and writes real records that other tests can touch at the same time.

None of these show up when a class runs alone, which is why the suite looks random.

How do you tell a parallel flake from a real bug?

  1. Read the error. UNABLE_TO_LOCK_ROW, DUPLICATE_USERNAME and other duplicate-value errors on test data point to concurrency.
  2. Rerun the class alone. The Salesforce CLI --synchronous flag runs the test methods of a single Apex class synchronously, per the plugin-apex documentation.
  3. Compare. Passes alone, fails in parallel: isolation problem. Fails both ways: a real defect. Fix it, do not retry it.
  4. Log it. Record the class, error and date. A class that flakes twice in a month goes to the top of the fix list.

How do you make Apex tests safe to run in parallel?

  1. Create all test data inside the test. Use @TestSetup or a data factory and drop SeeAllData=true. Tests that build their own data do not contend for org records.
  2. Keep writes inside the test's own records. Avoid updating shared setup records, the running user or anything a sharing recalculation might lock.
  3. Make unique fields unique per class. Prefix usernames and other unique values with the test class name plus a random number.
  4. Split unit tests from integration tests. Logic you can test without DML never takes a lock. Keep the heavy, data-bound tests in a smaller set you can watch closely.
  5. Mark proven classes. Winter '18 added @isTest(isParallel=true) to flag classes that can run in parallel without the default concurrency limits, as FishOfPrey covers. Add it only to classes that pass repeatedly in parallel runs.

Should you just enable Disable Parallel Apex Testing?

Only as a stopgap. The setting lives under Setup, Apex Test Execution, Options, and runs asynchronous tests one at a time. It removes concurrency flakes, but in orgs with many test classes a full run can take far longer. Some tools depend on the same switch: Gearset's documentation notes its test monitors use the Tooling API and therefore run tests in parallel unless you enable it.

Treat the checkbox as a debt marker. Turn it on to unblock a release, then fix the offending classes and turn it off again.

How do you run parallel Apex tests reliably in CI?

  • Run asynchronously by default. sf apex run test --test-level RunLocalTests gives you the parallel run your production deploys will see.
  • Capture machine-readable results. Add --result-format junit --output-dir so your pipeline can track failures per class over time, and --code-coverage to keep coverage visible.
  • Classify, then retry once. Rerun only failures that match a concurrency signature, synchronously. If the rerun passes, log a flake; if it fails, fail the build.
  • Watch the flake rate. A rising count is a test-design problem, not a platform one.

Blind retries are tempting, but they turn real defects into green builds. The same discipline applies when you change tooling, as covered in how to switch Salesforce DevOps tools without breaking your pipeline and our guide to migrating from Gearset to Serpent without downtime.

Point-and-click releases hit the same failures, because the tests still run on deploy. Our click deploy checklist covers what to verify first, and you can browse more how-tos in SF Guides.

Who is Tekunda?

Tekunda is the Salesforce consulting and product company that builds Serpent, a Salesforce DevOps platform with GitHub-based source control and automated deployment pipelines. If flaky tests are stalling your releases, compare plans on our pricing page.

FAQ

Does Salesforce run Apex tests in parallel by default?

Yes, asynchronous test runs execute classes concurrently unless Disable Parallel Apex Testing is enabled in Setup.

What causes UNABLE_TO_LOCK_ROW in Apex tests?

Two transactions want the same record, often a parent locked by a master-detail update, roll-up summary or sharing recalculation. The waiting one fails after 10 seconds.

Should I retry flaky Apex tests automatically?

Retry once, synchronously, and only for concurrency errors. Log every flake and fix the class rather than relying on retries.

Is isParallel=true enough to fix flaky tests?

No. It only marks a class as parallel-safe. The test still has to create its own data and use unique values.

Related Articles

Curious about faster shipping before you dive in? Let's talk

Commitment free!