Mocking HTTP Callouts
By the end of this lesson, you'll be able to:
- Explain why a real HTTP callout can't run inside a test
- Implement HttpCalloutMock to simulate an external response
- Test both a successful and a failed callout response
Prerequisites: "Test Data Factories"
Why real callouts can't run in a test
Apex tests explicitly cannot make real HTTP callouts — attempting one throws a CalloutException. This is deliberate: tests need to run reliably and repeatably regardless of whether an external system is actually available, fast, or even still exists months later, and they should never have side effects on a real third-party service (a later Integration module covers callouts fully; this lesson focuses purely on testing them).
Implementing a mock response
@isTest
public class ShippingRateMock implements HttpCalloutMock {
public HttpResponse respond(HttpRequest request) {
HttpResponse response = new HttpResponse();
response.setStatusCode(200);
response.setBody('{"rate": 45.50}');
return response;
}
}
A class implementing HttpCalloutMock defines exactly what response the mocked callout should return — here, a successful 200 with a fake JSON body, entirely fabricated by the test, with no real network request ever made.
Using the mock in a test
@isTest
static void getShippingRateReturnsParsedRate() {
Test.setMock(HttpCalloutMock.class, new ShippingRateMock());
Test.startTest();
Decimal rate = ShippingService.getShippingRate('12345');
Test.stopTest();
System.assertEquals(45.50, rate);
}
Test.setMock(HttpCalloutMock.class, new ShippingRateMock()) tells Apex: any real callout attempted during this test should be intercepted and answered by ShippingRateMock instead — ShippingService.getShippingRate() runs its actual logic unmodified, just receiving a fake response instead of a real one.
Testing a failure response too
@isTest
public class ShippingRateFailureMock implements HttpCalloutMock {
public HttpResponse respond(HttpRequest request) {
HttpResponse response = new HttpResponse();
response.setStatusCode(500);
response.setBody('Internal Server Error');
return response;
}
}
@isTest
static void getShippingRateHandlesServerError() {
Test.setMock(HttpCalloutMock.class, new ShippingRateFailureMock());
Test.startTest();
Decimal rate = ShippingService.getShippingRate('12345');
Test.stopTest();
System.assertEquals(null, rate); // however the service is designed to handle a failure
}
Exactly Module 31's "Testing Exceptions" lesson pattern, extended to callouts: a second mock class simulating a 500 error verifies the code's failure-handling path, not just its happy path — a scenario that would be genuinely difficult to reliably reproduce against a real external system on demand.
Exercise
Write a mock class OrderStatusMock returning a 200 response with the body '{"status": "shipped"}', then a test method using it.
Show hint
implements HttpCalloutMock, then Test.setMock(HttpCalloutMock.class, new OrderStatusMock());
Mocking HTTP Callouts Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
Apex forbids real HTTP callouts during tests — HttpCalloutMock lets a test simulate exactly what an external system would have returned, without ever actually calling it.