Salesforce enforces a nice discipline on developers - in order to deploy, Apex classes and triggers must demonstrate at least 75% code coverage across the code base. Code coverage is achieved by writing Unit Tests. Unit tests, properly designed, verify your logic and code paths.
For a unit test to work consistently as the code is deployed across orgs (from your sandbox/scratch org to CI orgs, to QA orgs, and finally to PROD), the test environment must be invariant to the test method. Salesforce recommends isolating Test Data from Organization Data in Unit Tests.
When you introduce
SeeAllData=true into your testmethods, you are, in effect, altering the test environment as your code moves from org-to-org during your devops/deployment pipeline.
Example: A SOQL query that depends on a certain setup of Pricebooks and
PricebookEntries might suddenly stop working as expected when those
records are CRUD by the org users.
This might not seem like a big deal to you, the Apex hero at your org, but that environment can change over time, long after you are gone or long after you have forgotten your reliance on the setup nuances of org data that makes your tests run successfully.
What is Org Data?
- Setup Data such as Users, Profiles, Groups, Folders, Roles, Sharing Rules, Custom Permissions, Custom Metadata, Custom Settings, etc.
- Non-setup Data such as records for: Accounts, Opportunities, Product2s, and custom objects
Mocking Org Data
Almost all Salesforce SObjects can be mocked in a testmethod so you don't need to use
SeeAllData=true. There are a variety of techniques, some easily enabled if you've adopted a design pattern.
- Mocking by inserting SObjects using DML including Test.loadData, Test factories, TestSetup-annotated methods, and direct DML within the testmethod.
- Mocking SObjects using
new XXX(fldA='foo', fldB='bar', ...) and passing these SObjects to methods under test or by using dependency injection to have methods return these SObjects for use by other methods. A good example of this is the Selector pattern on Trailhead.
- Mocking SObjects that don't support construction. Instead, use Json.deserialize.
AsyncApexJob is a good example of this.
- Mocking in-memory parent and child SObjects (see Third Party Testing Frameworks below)
If it seems like a lot of effort to mock up Accounts-Contacts-Opportunities-Quotes-Orders-etc (or some complex graph of custom objects), avoid falling into the
SeeAllData=true trap and instead decompose your testing into pieces, verifying that each layer handles its inputs, marshals the correct arguments to supporting services and generates expected outputs. Good software architecture aids immeasurably here. One resource to consider is the Apex Enterprise Patterns Trailmix.
What about the Org Data that can't be mocked?
Some Org Data is always available to the testmethod without recourse to
SeeAllData=true. For example, Folders, Profiles, StaticResources, Users. You should write your tests to be resilient so that if they require a specific Profile, that the test fails with an assert if that profile is not present.
I've mocked as much as possible, so when do I really need
Third-Party Testing Frameworks (Advanced Topics)
Books on Apex Testing Frameworks