Test External Services and HTTP Callouts in Apex Integration Tests (Developer Preview)

Test External Services and HTTP Callouts in Apex Integration Tests (Developer Preview)

Write Apex integration tests that call real HTTP endpoints, including external service endpoints, without requiring mock callouts. Integration tests relax callout restrictions and transaction rollback semantics, so you can validate real service interactions and assert on actual side effects in your scratch org. With the new @BeforeClass annotation, you can now set up test data shared across methods within an integration test class.

Where: This feature is available to scratch orgs in Lightning Experience and Salesforce Classic in Developer editions.

Important
Important This feature is available as a developer preview. This feature isn’t generally available unless or until Salesforce announces its general availability in documentation or in press releases or public statements. All commands, parameters, and other features are subject to change or deprecation at any time, with or without notice. Don’t implement functionality in production with these commands or tools.

Why: Previously, Apex integration tests were available only for Agentforce and Data 360 interactions. With this release, integration tests allow HTTP callouts to any endpoint, including External Services configured via Named Credentials. Validate a full request-response cycle against actual external systems in scratch orgs and catch issues that mocks can’t surface, such as serialization mismatches, authentication failures, and timeout behavior.

How: To use integration tests, first enable the ApexIntegrationTests feature in your scratch org definition file.

{
  "orgName": "My Company",
  "edition": "Developer",
  "features": ["ApexIntegrationTests"]
}

To write an integration test class, use the @IntegrationTest annotation on the class and each test method. To set up test data shared across all methods, use the @BeforeClass annotation. Use the @TearDown method to clean up data committed during test method execution.

Note
Note If a mock is registered via Test.setMock(), the mock takes precedence over real callouts. Remove mocks to test real endpoints.
@IntegrationTest
public with sharing class ExternalServiceIntegrationTest {
    @BeforeClass
    static void setup() {
        Account a = new Account(Name = 'PaymentTestAccount');
        insert as user a;
        // Platform auto-commits. No commitTestOnly() needed in @BeforeClass
    }

    @IntegrationTest
    public static void testExternalServiceCallout() {
        Account a = [SELECT Id FROM Account
            WHERE Name = 'PaymentTestAccount'
            WITH USER_MODE];
        // Real HTTP callout — no mock required
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('callout:PaymentGateway/verify/' + a.Id);
        req.setMethod('GET');
        HttpResponse res = h.send(req);
        Assert.areEqual(200, res.getStatusCode());
        Assert.isTrue(res.getBody().contains('verified'));
    }

    @TearDown
    public static void tearDown() {
        delete [SELECT Id FROM Account WHERE Name = 'PaymentTestAccount'];
    }
}

To run an integration test, use the Tooling API REST resource /services/data/vXX.X/tooling/runTestsAsynchronous/. You can run only one concurrent integration test asynchronously. Synchronous testing isn’t available for integration tests.