If you've ever tried to push Apex code to a production org, you've met Salesforce's deployment gatekeeper: the mandatory test run. In 2026, those rules haven't relaxed at all — and that's deliberate. Tests aren't bureaucracy; they're how a shared, multi-tenant platform stays trustworthy when thousands of developers ship code every day.
Why Salesforce enforces test coverage
Salesforce executes your code alongside everyone else's in a multi-tenant architecture. A careless trigger on your org can't be allowed to undermine the platform's reliability for your users. Mandatory tests serve two purposes:
- Deployment safety. Production deployments require a passing test run. If your tests fail, your metadata stays in the sandbox. Simple as that.
- Regression insurance. Orgs evolve constantly — admins add flows, validation rules, and required fields. A solid test suite catches the breakage before your users do.
The coverage rules, precisely
Here is what the platform actually demands before a production deployment:
- At least 75% of all Apex code in the org must be executed by tests.
- Every trigger must have some coverage — an untested trigger blocks deployment even if the org-wide number looks fine.
- All test methods must pass. No failures, no uncaught exceptions.
- Test classes themselves don't count toward the 75%.
Notice what's missing from that list: any requirement that your tests be good. A test that executes code without asserting anything still inflates the percentage. Which brings us to the real problem.
Stop gaming coverage; start asserting
Coverage is a floor, not a finish line. A test without System.assert calls proves nothing except that your code doesn't crash on one narrow path. Meaningful tests assert outcomes:
- Assert the business result, not the implementation detail. ("The opportunity moved to Closed Won" beats "the method returned true.")
- Test the unhappy paths: validation failures, null inputs, and governor-limit-adjacent bulk sizes.
- Cover every branch of your conditionals — both sides of each
if/elseand every ternary outcome.
Write tests you'd trust to run at 2 AM during a release window. We walk through the full setup in our test classes and code coverage guide.
Bulk-safe test data patterns
Tests that insert a single record and call it a day are lying to you. Real orgs process data in bulk — triggers fire on up to 200 records at a time. Build that reality into your tests from the start:
- Create your own data. Never depend on existing org data (
SeeAllData=trueis a trap that makes tests fail in fresh sandboxes). Generate records that mirror real business scenarios, including related records. - Use
@TestSetup. One setup method builds shared data once per test class, keeping tests fast and consistent. - Centralize with a Test Data Factory. A single utility class that produces Accounts, Contacts, and Opportunities with sensible defaults saves everyone on the team from reinventing fixtures.
- Test in bulk. Insert 200 records, not one. That's where SOQL-in-loop bugs and governor-limit failures hide.
@isTest private class AccountTriggerTest { @TestSetup static void makeData() { List<Account> accts = new List<Account>(); for (Integer i = 0; i < 200; i++) { accts.add(new Account(Name = 'Test ' + i)); } insert accts; } @isTest static void bulkInsertSetsIndustry() { Test.startTest(); // trigger logic under test runs against the @TestSetup data Test.stopTest(); Integer flagged = [SELECT COUNT() FROM Account WHERE Industry = 'Technology']; System.assertEquals(200, flagged, 'All bulk-inserted accounts should be flagged'); } } Test.startTest() and Test.stopTest() also reset governor limits and force asynchronous code — future methods, queueables, batch jobs — to run synchronously, which is essential for testing anything @future or scheduled.
Deployment gotchas that still bite in 2026
- Coverage evaporates on edit. The moment you modify a class, its coverage data is cleared until tests run again. Re-run after every change.
- Mixed DML errors. Creating a User and an Account in the same transaction blows up. Wrap user-context setup in
System.runAs(), which also lets you verify sharing rules and profile behavior. - Run test classes individually when debugging. One class at a time makes failures far easier to isolate than a full-org run.
- Aim above the minimum. 75% gets you deployed; targeting 90% or more across classes and triggers gives you headroom for the inevitable coverage dip when someone edits a class the night before a release.
Good tests are documentation that executes. They tell the next developer what the code is supposed to do — and they scream when it stops doing it. Write them like the next person reading them is you, six months from now, during an incident.
Originally published at Way2Force.