Virtually each profitable Salesforce implementation reaches a degree the place the event patterns that labored on day one begin to break down. What started as a nimble atmosphere finally grows into a big, complicated org (or set of orgs), usually containing 1000’s of Apex lessons and sophisticated enterprise logic. At that time, a once-straightforward “Run All Exams” deployment can balloon right into a multi-hour course of that grinds improvement to a halt.
When this deployment tax turns into a burden, it modifications the group’s relationship with the codebase. Sustaining excessive velocity requires architecting for deployment effectivity.
Apex unit exams are generally among the many largest bottlenecks in deployment. First, they take a very long time to run. And second, exams that nondeterministically change between passing and failing (typically known as “flappers”) could cause deployments to fail hours into execution.
This publish describes three sensible strategies for making deployment take a look at runs each sooner and extra dependable:
- Write sooner, extra dependable unit exams with database mocking
- Execute the fitting exams utilizing
RunRelevantTests - Execute exams extra effectively post-deployment
Write sooner, extra dependable unit exams with database mocking
When your utility code makes a callout to different companies, exams should present mocks of the companies’ responses to make use of as an alternative of genuinely executing the callout. That is for 2 causes:
- Callouts could also be long-running as a result of they wait on an exterior server’s response: a REST API that takes a number of seconds below regular load can push a take a look at run properly previous timeout thresholds.
- Executing callouts in exams creates flappers as a result of the exterior server introduces variables your take a look at can’t management: the endpoint is quickly unreachable, the sandbox IP is blocked by a firewall rule, or the third-party API returns a 429 throughout a rate-limit window.
Mocks, in contrast, can reply to requests in a means that’s each fast and deterministic.
Callouts, nonetheless, should not the one operation that may be sluggish or non-deterministic. For instance, database calls (SELECT statements and DML) take significantly longer than in-memory code execution. They’ll additionally fail unpredictably due to row lock contentions, which trigger UNABLE_TO_LOCK_ROW exceptions.
Luckily, you possibly can mock many long-running or unpredictable operations in Apex exams with intelligent class design. Step one is to isolate your calls to the operation into strategies in a separate class. These strategies needs to be non-static as a result of later you’ll use polymorphism to use various implementations. For instance, contemplate the next class:
public class OpportunityService {
public void createDiscountedOpp(Id accId, Decimal quantity) {
Account acc = [SELECT Rating FROM Account WHERE Id = :accId];
Decimal low cost = (acc.Ranking == 'Sizzling') ? 0.20 : 0.10;
Alternative opp = new Alternative( AccountId = accId,
Quantity = quantity * (1 - low cost),
StageName="Prospecting" );
insert opp;
}
}
This class is tightly coupled to the database. As written, it’s not possible to check it with out accessing the database twice: as soon as within the SELECT assertion and as soon as within the insert operation. This not solely slows down any take a look at of the code, but in addition introduces the chance of row lock rivalry throughout take a look at runs because of the insert operation.
It is a primary architectural drawback: enterprise logic and database interfacing needs to be separate issues, however the OpportunityService class tries to deal with each. You may keep correct separation of issues by refactoring the database operations right into a separate class as follows:
public class OpportunityServiceDbHandlerImpl {
public Account getAccountWithRatingById(Id accId) {
return [SELECT Rating FROM Account WHERE Id = :accId];
}
public void insertOpp(Alternative opp) {
insert opp;
Then OpportunityService turns into:
public class OpportunityService {
non-public OpportunityServiceDbHandlerImpl dbHandler;
public OpportunityService() {
dbHandler = new OpportunityServiceDbHandlerImpl();
}
public void createDiscountedOpp(Id accId, Decimal quantity) {
Account acc = dbHandler.getAccountWithRatingById(accId);
Decimal low cost = (acc.Ranking == 'Sizzling') ? 0.20 : 0.10;
Alternative opp = new Alternative( AccountId = accId,
Quantity = quantity * (1 - low cost),
StageName="Prospecting" );
dbHandler.insertOpp(opp);
}
}
Now that you simply’ve separated issues, exams can extra simply confirm the enterprise logic in createDiscountedOpp() with out really accessing the database. Begin by abstracting an interface from OpportunityServiceDbHandlerImpl and making the category implement it. Right here’s the interface:
public interface OpportunityServiceDbHandler {
Account getAccountWithRatingById(Id accId);
void insertOpp(Alternative opp);
}
Use this interface wherever attainable in OpportunityService, and provides exams an opportunity to inject an alternate implementation:
public class OpportunityService {
non-public OpportunityServiceDbHandler dbHandler;
public OpportunityService() {
this(new OpportunityServiceDbHandlerImpl());
}
@TestVisible non-public OpportunityService(
OpportunityServiceDbHandler dbHandler) {
this.dbHandler = dbHandler;
}
public void createDiscountedOpp(Id accId, Decimal quantity) {
/* Identical implementation as earlier than */
}
}
When testing OpportunityService, inject another, trivial implementation of OpportunityServiceDbHandler:
@IsTest
non-public class OpportunityServiceTest {
non-public class MockOpportunityServiceDbHandler
implements OpportunityServiceDbHandler {
public Alternative lastInsertedOpp;
public Account getAccountWithRatingById(Id accId) {
return new Account (Id = accId,
Ranking = 'Sizzling');
}
public void insertOpp(Alternative opp) {
lastInsertedOpp = opp;
}
}
@IsTest
static void shouldCalculateGoldDiscount() {
// SET UP
MockOpportunityServiceDbHandler mockHandler =
new MockOpportunityServiceDbHandler();
OpportunityService service = new OpportunityService(
mockHandler);
Decimal inputAmount = 100.00;
Id fakeAccId = (Id)'001000000000000AAA';
Decimal expectedAmount = 80.00; // 20% low cost
// EXECUTE
service.createDiscountedOpp(fakeAccId, inputAmount);
// CHECK RESULTS
Alternative inserted = mockHandler.lastInsertedOpp;
Assert.isNotNull(inserted, 'No Alternative inserted');
Assert.areEqual(expectedAmount,
inserted.Quantity,
'Incorrect low cost utilized');
}
}
This take a look at validates the enterprise logic within the OpportunityService implementation with out testing the database. The code that instantiates OpportunityService determines which particular implementation of OpportunityServiceDbHandler the occasion makes use of, a sample referred to as dependency injection. Injecting a take a look at implementation of database dealing with operations is environment friendly as a result of the aim of the take a look at is to validate the enterprise logic in OpportunityService quite than the Salesforce implementation of normal database operations.
Mock dependencies with the Apex Stub API
Moderately than writing a concrete take a look at implementation of your interface, the Apex Stub API helps you to generate a mock object at runtime and outline its conduct inline. It’s a lighter-weight various whenever you don’t want the total management of a hand-written mock class.



Database isolation will not be a common mandate. Testing triggers, for instance, requires actual DML execution, as there isn’t a substitute for validating the execution order. Past triggers, you should use exams to confirm system boundaries; counting on assumptions isn’t any substitute for precise database testing. Such exams aren’t unit exams; they’re integration or purposeful exams. Use them sparingly: solely when you might want to take a look at a set off or a very vital or complicated integration circulation. The overwhelming majority of your exams needs to be true unit exams. Adhering to this normal accelerates take a look at execution and simplifies deployments.
Execute the fitting exams utilizing RunRelevantTests
For a manufacturing launch, operating each take a look at is important. A category that passes its personal exams in isolation can nonetheless break a course of three layers away; full regression testing helps expose these hidden failures.
Nonetheless, in a corporation with a mature pipeline, operating all exams at each stage can develop into expensive. A single code change goes by means of a number of deployments earlier than reaching manufacturing. Even minor take a look at inefficiencies compound, so this further pipeline time can add up shortly.
On the different excessive, bypassing exams in decrease environments is self-defeating. Omitting these checks can corrupt your integration, UAT, and staging environments with defects that masks the unique supply of failure. A secure pipeline should validate modifications at each stage to forestall defects from propagating into downstream environments.
Whereas operating chosen exams represents a stability between these extremes, counting on handbook take a look at choice is an inefficient deployment technique. This strategy introduces administrative overhead that stalls the pipeline and creates a brand new failure mode: choosing the fallacious exams. The integrity of the discharge mustn’t rely on a deployer’s skill to decide on which exams matter. An automatic, goal normal is required.
Spring ’26 introduces RunRelevantTests. This take a look at stage will increase deployment velocity by choosing solely exams related to your deployed modifications.
Be aware: As a result of this function is in beta, it mustn’t but be built-in into manufacturing pipelines.
RunRelevantTests depends on the compile-time dependency graph; it could possibly’t detect dependencies launched by means of dynamic dispatch or dependency injection patterns.When a category holds a variable typed straight as DelegateImpl and calls doSomething() on it, the dependency graph can establish a compile-time relationship between the caller and DelegateImpl. Runtime dynamic dispatch introduces a dependency that exists at runtime however will not be seen to the dependency graph.
Contemplate the next instance:
public interface Delegate {
public void doSomething();
}
public class DelegateImpl implements Delegate {
public void doSomething() {
// some code
}
}
public class Caller {
public void makeCall(String delegateImplementationName) {
Kind delegateImplementation =
Kind.forName(delegateImplementationName);
Delegate delegate = (Delegate) delegateImplementation.newInstance();
delegate.doSomething();
}
}
The dependency construction above creates a blind spot: whereas Caller is determined by Delegate at compile time, it has no compile-time hyperlink to DelegateImpl. The dependency graph can not monitor the runtime decision of DelegateImpl into Caller.makeCall(). RunRelevantTests could omit a take a look at required to validate the change. You may shut this hole by declaring the dependency explicitly within the @IsTest annotation. The testFor parameter, illustrated beneath, causes CallerTest to be included at any time when DelegateImpl modifications.
@IsTest(testFor="ApexClass:DelegateImpl")
public class CallerTest {
// exams
}
You probably have a category with many dynamic dependencies, quite than itemizing all of them within the testFor attribute, you possibly can specify that the take a look at ought to at all times be run throughout RunRelevantTests deployments. The crucial parameter, illustrated beneath, causes CallerTest to be included at any time when any Apex code modifications:
@IsTest(crucial=true)
public class CallerTest {
// exams
}
Be sparing with crucial=true, nonetheless. Utilizing it the place it’s not wanted reduces the time financial savings afforded by RunRelevantTests.
Execute exams extra effectively post-deployment
At some phases of supply, there may be an possibility usually sooner than operating exams throughout deployment. That possibility entails deferring most or all take a look at execution till after deployment completes. That is acceptable for deployment to scratch orgs, corresponding to you would possibly do as a primary step of pull request validation earlier than the code is merged to a source-of-truth department. Be aware that you’ll nonetheless must carry out integration testing, usually in sandbox environments, later in your pipeline, however operating exams earlier than code even enters the codebase will catch some bugs on the best time to diagnose them.
A take a look at run that’s a part of a deployment might be a lot slower than a run (even of the identical exams) that isn’t a part of the deployment. Understanding why requires perception into the deployment course of itself.
While you run exams as a part of a deployment, the deployment will not be dedicated till the exams full efficiently. So throughout deployment take a look at runs, the exams want to have the ability to see the modified metadata, however these modifications aren’t but dedicated to the database. Because of this the exams must run in the identical database transaction because the deployment, which in flip signifies that they need to run in the identical database transaction as one another.
Earlier than every take a look at runs, Salesforce locations a database savepoint, which Salesforce rolls again to on the finish of the take a look at. This prevents a take a look at that inserts or modifies information from affecting exams that run after it. However when two exams share a database transaction, they will’t run concurrently, or they might have an effect on each other. Because of this, Salesforce doesn’t parallelize take a look at runs that occur as a part of a deployment.

A take a look at run that isn’t a part of a deployment is totally different. A number of exams can run concurrently with out affecting one another so long as they’re in numerous database transactions. Except you’ve particularly chosen “Disable Parallel Apex Testing,” Salesforce takes benefit of this reality and makes use of a number of threads to run non-deployment exams.
Doing this implies you threat committing metadata that may make your exams fail and gained’t discover out till the take a look at run completes. However in case you’re deploying to a disposable group corresponding to a scratch org spun up for pull-request-time testing, that is positive; if the exams fail, you possibly can reject the pull request and delete the org.
Begin with one repair and construct from there
Undertake the patterns outlined on this publish incrementally to align your group with the Dependable and Composable capabilities of the Effectively-Architected Framework.
Begin by figuring out your most-deployed lessons and decoupling enterprise logic from DML or SOQL calls. Use the Dependency Injection sample to extract the database operations behind an interface; this enables your unit exams to run with out touching the org. Subsequent, add @IsTest(testFor=...) annotations to the corresponding take a look at lessons to make sure RunRelevantTests can choose them accurately. Lastly, for scratch org pull request validation, transfer your take a look at execution to a post-deploy step to allow computerized parallelization with none extra pipeline overhead.
These optimizations will enhance your pipeline, however they work inside your present deployment mannequin. To maneuver extra of the deployment tax out of your launch window, you’ll must optimize supply processes and modernize the underlying structure.
Subscribe to the Salesforce Architect Digest on LinkedIn
Get month-to-month curated content material, technical sources, and occasion updates designed to help your Salesforce Architect journey.




