# Apex mocks, stubs and advanced test techniques

*Platform Developer II Study Guide · Testing, Debugging, and Deployment · Last updated October 16, 2026 · https://www.certifyforce.com/study-guide/platform-developer-ii/testing-debugging-and-deployment/apex-mocks-stubs-and-advanced-test-techniques*

Pick the right callout mock (HttpCalloutMock, static resource mocks, WebServiceMock), isolate classes with the Stub API and dependency injection, and control test context with @TestVisible, @testSetup, event delivery, fixed SOSL results, setCreatedDate, runAs and Assert-based negative and bulk tests.

- Certification: Salesforce Platform Developer II
- Exam section: Testing, Debugging, and Deployment
- Study guide: https://www.certifyforce.com/study-guide/platform-developer-ii

**Official exam objective:**

> Apply advanced techniques and tools for testing Apex classes and triggers, such as mocks and stubs.

## What the exam expects

- Choose between `HttpCalloutMock`, `StaticResourceCalloutMock`, `MultiStaticResourceCalloutMock` and `WebServiceMock` for a given callout, and fix a test that does DML before a mocked callout.
- Isolate a class with the Stub API (`Test.createStub()` plus `StubProvider`), inject the stub, and name what the Stub API can't mock.
- Control the test context: `@TestVisible`, `@testSetup` and static variables, `Test.loadData()`, `Test.setFixedSearchResults()`, `Test.setCreatedDate()`, batch and event delivery, and `System.runAs()` with class sharing modes.
- Write negative and bulk tests that follow Salesforce's testing best practices.

Key terms: **mock** (a test-only object that returns a canned callout response); **stub** (a runtime-generated subclass whose methods `StubProvider.handleMethodCall()` answers); **dependency injection** (handing a collaborator to a class instead of letting it `new` its own); **test event bus** (the separate bus that holds platform and change events in tests until they are delivered); **static context** (the static variables of a test class, reinitialized per test method).

This unit assumes the basics in the Platform Developer guide's *Writing and running Apex and Flow tests* (`@IsTest`, data isolation, `startTest`/`stopTest`, coverage).

## Key facts

| Fact | Detail | Source |
|---|---|---|
| `Test.setMock` scope | HTTP-class callouts and WSDL-generated code only | [Test Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_test.htm) |
| Per-endpoint static bodies | `MultiStaticResourceCalloutMock.setStaticResource(endpoint, name)` | [Static Resource Callout Mocks](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_static.htm) |
| SOAP mock | `WebServiceMock.doInvoke()` puts `response_x` in the response map | [Test Web Service Callouts](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_wsdl2apex_testing.htm) |
| DML then mocked callout | `startTest` before `setMock`; DML outside the block | [DML and Mock Callouts](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_dml.htm) |
| Stub API can't mock | Static, private, properties, triggers, inner classes, system types, Batchable, private-only constructors | [Stub API](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_stub_api.htm) |
| `@testSetup` | One per class; static context reset before each test method | [Using Test Setup Methods](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_testsetup_using.htm) |
| SOSL in tests | Empty results unless `Test.setFixedSearchResults()` | [SOSL in Unit Tests](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_SOSL.htm) |
| Batch in tests | Only one `execute` call can be tested | [Use Batch Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm) |
| Change events in tests | `enableChangeDataCapture()` first; up to 500 events delivered | [Test Change Event Triggers](https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_trigger_testing.htm) |
| `runAs` and called classes | Called method uses its own class's sharing mode | [Using the runAs Method](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_tools_runas.htm) |
| Bulk trigger tests | At least 20 records | [Testing Best Practices](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_best_practices.htm) |

## Check yourself

- Why does a test that inserts an Account before a mocked callout fail?
- When does a stub from `Test.createStub()` actually run?
- Why is a static variable assigned in `@testSetup` null in a test method?
- What must a test call so SOSL returns a record it inserted?
- When must `Test.enableChangeDataCapture()` be called?

## Sources

- [Build a Mocking Framework with the Stub API](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_stub_api.htm)
- [StubProvider Interface](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_interface_System_StubProvider.htm)
- [Testing HTTP Callouts by Implementing the HttpCalloutMock Interface](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_httpcalloutmock.htm)
- [Testing HTTP Callouts Using Static Resources](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_static.htm)
- [Test Web Service Callouts](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_wsdl2apex_testing.htm)
- [Performing DML Operations and Mock Callouts](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_dml.htm)
- [Testing Best Practices](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_best_practices.htm)
- [TestVisible Annotation](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_testvisible.htm)
- [Using Test Setup Methods](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_testsetup_using.htm)
- [Test Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_test.htm)
- [Use Batch Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm)
- [Test Change Event Triggers](https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_trigger_testing.htm)
- [Testing Your Platform Event in Apex](https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_event_apex_tests.htm)
- [Adding SOSL Queries to Unit Tests](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_SOSL.htm)
- [Loading Test Data](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_load_data.htm)
- [Using the runAs Method](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_tools_runas.htm)
- [Assert Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_System_Assert.htm)

## About the full unit

The "Core concepts", "Exam traps" and "Worked scenario" sections of this unit, its 15 linked practice questions, and unlimited timed mock exams are included with the Platform Developer II pack (USD $19): https://www.certifyforce.com/practice-exams
