System.QueryException: List has no rows for assignment to SObject (in test context)
Your Apex test failed because it expects org data that doesn't exist in the test context. By default, tests run in **isolation** — they can't see existing org data. Either build the data the test needs in `@TestSetup`, or (less ideal) opt-in to `@isTest(SeeAllData=true)`.
Also seen astest class can't see records·no rows in test·Test class data isolation·@isTest SeeAllData
Apex tests run in a sandbox-within-the-sandbox: by default, no org data is visible inside a test method. Every record the test needs must be created by the test itself.
Why isolation exists
The platform isolates tests because:
- Tests should be deterministic — running on a different org with different data shouldn't change the outcome
- Tests should be fast — not requiring the full org's record set to be queried
- Tests should not corrupt org data — DML inside tests is rolled back at the end
The cost: every test must build its own data.
The right pattern: @TestSetup
@isTest
public class AccountServiceTest {
@TestSetup
static void setup() {
Account a = new Account(Name = 'Test Acme', Industry = 'Tech');
insert a;
insert new Contact(LastName = 'Smith', AccountId = a.Id);
}
@isTest
static void emailFormatting_works() {
Account a = [SELECT Id, Name FROM Account WHERE Name = 'Test Acme' LIMIT 1];
// ... test logic ...
}
}
@TestSetup runs once before each @isTest method. The data it creates is visible to every test in the class. Test isolation rolls everything back at the end of the class.
The escape hatch: @isTest(SeeAllData=true)
@isTest(SeeAllData=true)
static void usesOrgData() {
Account a = [SELECT Id FROM Account WHERE Name = 'Production Account' LIMIT 1];
// ... test ...
}
This makes org data visible to the test. Use sparingly. Reasons against:
- Tests become coupled to specific org data — they break when an admin renames a record
- Tests aren't portable across orgs — production tests pass; sandbox tests fail because the data doesn't match
- New developers can't run the test without first knowing what data to provision
- Bad pattern flagged by
@SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts')and similar tools
There are legitimate cases — querying record types, profiles, queues, custom metadata that the test setup can't easily mock. For those, document why SeeAllData=true is necessary in the test method's comment.
A subtler case: object-level data
Some objects ARE visible in test context by default:
- Profile, UserRole, RecordType
- CustomMetadataType records
- StaticResource
The platform exposes these because they're metadata, not data. So [SELECT Id FROM Profile WHERE Name = 'Standard User'] works in a test class without SeeAllData=true.
If your test queries a record type or profile and gets no results, the issue isn't data isolation — it's that the record type / profile doesn't exist by that name.
Migration from SeeAllData=true
If your codebase has many SeeAllData=true tests:
- Identify the records each test depends on
- Add a
@TestSetupthat creates them - Remove
SeeAllData=true - Run; fix any breakage
This is tedious but pays off — your tests become fast, isolated, and portable.
