Skip to content

Commit ac2c8d5

Browse files
committed
Query Stack documentation
1 parent cf1ce0f commit ac2c8d5

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

website/docs/advanced-usage/mocking.md

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar_position: 30
55
# Mocking
66

77
Mocking provides a way to substitute records from a database with some prepared data. Data can be prepared in the form of SObject records and lists in Apex code or Static Resource `.csv` file.
8-
Mocked queries won't make any SOQLs and simply return data set in method definition, mock __will ignore all filters and relations__, what is returned depends __solely on data provided to the method__. Mocking is working __only during test execution__. To mock SOQL query, use `.mockId(id)` method to make it identifiable. If you mark more than one query with the same ID, all marked queries will return the same data.
8+
Mocked queries won't make any SOQLs and simply return data set in method definition. Mock __will ignore all filters and relations__; what is returned depends __solely on data provided to the method__. Mocking works __only during test execution__. To mock a SOQL query, use the `.mockId(id)` method to make it identifiable. If you mark more than one query with the same ID, all marked queries will return the same data.
99

1010
```apex title="ExampleController.cls"
1111
public with sharing class ExampleController {
@@ -23,13 +23,42 @@ public with sharing class ExampleController {
2323
}
2424
```
2525

26-
Then in tests simply pass data you want to get from Selector to `SOQL.mock(id).thenReturn(data)` method. Acceptable formats are: `List<SObject>` or `SObject`. Then during execution Selector will return the desired data.
26+
Then in tests simply pass data you want to get from the Selector to the `SOQL.mock(id).thenReturn(data)` method. Acceptable formats are: `List<SObject>`, `SObject`, `Integer` (for count queries), or `List<Map<String, Object>>` (for aggregate results). During execution, the Selector will return the desired data.
2727

2828
## Insights
2929

30+
### Mocking Stack Functionality
31+
32+
SOQL Lib implements a sophisticated mocking system that supports multiple sequential mocks for the same query identifier. This enables complex testing scenarios where the same query needs to return different results across multiple executions.
33+
34+
**How the Stack Works:**
35+
36+
Each call to `SOQL.mock(mockId)` creates a new mock entry and adds it to a list (stack) associated with that mock ID. When queries are executed:
37+
38+
- **Single Mock**: If only one mock exists for the ID, it's reused for all executions
39+
- **Multiple Mocks**: Mocks are consumed in FIFO (First In, First Out) order - each execution removes and returns the first mock from the stack
40+
41+
```apex
42+
// Setup multiple sequential mocks
43+
SOQL.mock('testQuery').thenReturn(new Account(Name = 'First Call'));
44+
SOQL.mock('testQuery').thenReturn(new Account(Name = 'Second Call'));
45+
SOQL.mock('testQuery').thenReturn(new Account(Name = 'Third Call'));
46+
47+
// First execution returns "First Call", then removes that mock
48+
Account result1 = SOQL.of(Account.SObjectType).mockId('testQuery').toObject();
49+
50+
// Second execution returns "Second Call", then removes that mock
51+
Account result2 = SOQL.of(Account.SObjectType).mockId('testQuery').toObject();
52+
53+
// Third execution returns "Third Call", then removes that mock
54+
Account result3 = SOQL.of(Account.SObjectType).mockId('testQuery').toObject();
55+
56+
// Fourth execution would fail - no more mocks available
57+
```
58+
3059
### Id Field Behavior
3160

32-
The `Id` field is always included in mocked results, even if it wasnt explicitly specified. This is designed to mirror standard SOQL behavior — Salesforce automatically includes the `Id` field in every query, even when its not listed in the `SELECT` clause.
61+
The `Id` field is always included in mocked results, even if it wasn't explicitly specified. This is designed to mirror standard SOQL behavior — Salesforce automatically includes the `Id` field in every query, even when it's not listed in the `SELECT` clause.
3362

3463
```apex
3564
List<Account> accounts = [SELECT Name FROM Account LIMIT 3];
@@ -95,14 +124,14 @@ for (Account mockedResult : result) {
95124
In this case:
96125
- Although `Description` and `Website` were present in the mocked data, they are removed because they weren’t part of the query.
97126
- Only fields explicitly defined in `.with()` (plus `Id` by default) remain.
98-
Account `Description` and `Website` are null, even though they were specified. Hovever SOQL specified only for `Account.Name`, so additional field are stripped.
127+
Account `Description` and `Website` are null, even though they were specified. However, SOQL specified only `Account.Name`, so additional fields are stripped.
99128

100129
**Note:**
101130
Currently, this field-stripping behavior applies only to simple fields (such as `Name`, `Description`, etc.) and subqueries. Additional subqueries are also removed — only the explicitly queried subqueries remain.
102131

103132
Relationship fields and queries using functions are not yet covered by this logic. This means that SOQL queries involving relationship records or functions (like `COUNT`, `AVG`) will return the exact mock defined in the unit test. This may be addressed in future enhancements.
104133

105-
### Queried Issued Count
134+
### Queries Issued Count
106135

107136
Mocked queries in SOQL Lib are counted towards the SOQL query limit, just like real queries. If the number of issued queries exceeds the limit, SOQL Lib will throw:
108137

@@ -179,7 +208,7 @@ private class ExampleControllerTest {
179208
180209
@IsTest
181210
static void getPartnerAccountsCount() {
182-
SOQL.setCountMock('mockingQuery', 2);
211+
SOQL.mock('mockingQuery').thenReturn(2);
183212
184213
Integer result = SOQL.of(Account.sObjectType).count().mockId('mockingQuery').toInteger();
185214
@@ -190,13 +219,13 @@ private class ExampleControllerTest {
190219

191220
## Sub-Query
192221

193-
To mock a sub-query we need to use deserialization mechanism. There are two approaches, using JSON string or Serialization/Deserialization.
194-
Then after deserialization to desired SObjectType, pass the data to SOQL by calling `.mock` method.
222+
To mock a sub-query, we need to use a deserialization mechanism. There are two approaches: using JSON string or Serialization/Deserialization.
223+
After deserialization to the desired SObjectType, pass the data to SOQL by calling the `.mock` method.
195224

196225

197226
_Using JSON String_
198227

199-
By passing simple String, it is possible to write non-writable fields, like `Name` on Contact object.
228+
By passing a simple String, it is possible to write non-writable fields, like `Name` on the Contact object.
200229

201230
```apex
202231
@IsTest
@@ -222,7 +251,7 @@ static void getAccountsWithContacts() {
222251

223252
_Using Serialization/Deserialization_
224253

225-
Using this approach it is possible to bind data with additional logic, like using Test Data Factory.
254+
Using this approach, it is possible to bind data with additional logic, like using a Test Data Factory.
226255

227256
```apex
228257
@IsTest

0 commit comments

Comments
 (0)