How to Write Test Class for Invokable and @Future Callout?

Question:
I’m new to Apex and trying to learn as much as possible. I have two Apex classes that are working fine in my org.
The first class is an Invokable Apex class. This class is triggered by a Process Builder when certain conditions are met on the Lead object. It sends the lead’s information (ID, email, first name, and last name) to another class that handles the @Future callout.
The second class is the @Future callout class, which makes a POST request to an external REST API, sending the lead data. The external system returns an ID, which is then used to update the lead record.
Although both classes are functioning correctly, I’m struggling to write the test class for them as I’ve never written Apex test classes before.
Here are the two classes:
1. Invokable Apex Class:
public class MakeCallout {
@InvocableMethod
public static void invokeleadcallout(list<Lead> Leads) {
// Call the future method
WS_Lead.Notification(Leads[0].id, Leads[0].Email, Leads[0].Firstname);
}
}
2. WS Callout Class:
global class WS_Lead {
@future (callout=true)
public static void Notification(id lid, String name) {
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
req.setEndpoint('https://google.com');
req.setMethod('POST');
req.setHeader('Content-Type','application/x-www-form-urlencoded');
req.setBody('name='+EncodingUtil.urlEncode(name, 'UTF-8'));
req.setTimeout(120000);
try {
res = http.send(req);
System.debug(res.getbody());
Dom.Document docx = new Dom.Document();
docx.load(res.getbody());
Dom.XmlNode xroot = docx.getRootElement();
String U_Id = xroot.getAttributeValue('U_Id', null);
System.debug(U_Id);
Lead le = new Lead(id=lid);
le.ID__c = U_Id;
update le;
} catch (System.CalloutException e) {
System.debug('Callout error: ' + e);
System.debug(res.toString());
res.getbody();
}
}
}
Can anyone provide a proper way to write a test class for these two Apex classes?
Answer:
To test Apex classes that involve HTTP callouts and future methods, you need to use a combination of the @isTest
annotation, Test.startTest()
, Test.stopTest()
, and mocking HTTP responses using HttpCalloutMock
. Below is an example of how to test both the Invokable method and the @Future callout method:
Boost your Salesforce career with top-notch Salesforce training in Australia, offering hands-on projects and expert guidance for both beginners and professionals.
Test Class:
@isTest class MakeCalloutTest {
// Mock class to simulate HTTP response
class EchoHttpMock implements HttpCalloutMock {
HttpResponse res;
EchoHttpMock(HttpResponse r) {
res = r;
}
// This is the HttpCalloutMock interface method
public HttpResponse respond(HttpRequest req) {
return res;
}
}
@isTest static void test() {
// Avoid using live data in tests
List<Lead> leads = new List<Lead>{ new Lead(LastName='Test', Company='test') };
insert leads;
// Define the mock response for the HTTP callout
HttpResponse res = new HttpResponse();
res.setBody('<?xml version="1.0" encoding="utf-8"?><root U_Id="12345"></root>');
res.setStatusCode(200);
// Set the mock response for the callout
Test.setMock(HttpCalloutMock.class, new EchoHttpMock(res));
// Start the test execution
Test.startTest();
// Enqueue the future call
MakeCallout.invokeleadcallout(leads);
// Trigger future method execution
Test.stopTest();
// Verify the results
leads = [SELECT Id__c FROM Lead];
System.assertEquals('12345', leads[0].Id__c);
}
}
Explanation:
- HttpCalloutMock: A mock class is created to simulate the HTTP response from the external service. The mock class implements the
HttpCalloutMock
interface and provides the response when a callout is made. - Test.setMock: This method sets the mock class that simulates the HTTP response. You define what the response should look like, including the body and status code. In this example, the response body is an XML containing a
U_Id
. - Test.startTest() and Test.stopTest(): These methods are used to enclose the actual method calls being tested.
Test.startTest()
starts the test, andTest.stopTest()
ensures that the future method is executed within the test context. - Assert Statements: After running the test, you verify if the lead’s custom field (
Id__c
) was correctly updated with theU_Id
returned from the external API.
Key Notes:
- This test class does not cover the exception handling part of the
try-catch
block. To fully test the callout, you can manually trigger aCalloutException
in the mock class to simulate the error scenario. - The test ensures that the lead record is updated with the
U_Id
returned from the external system.
This approach helps you simulate callouts in your tests and properly validate that your @Future methods and Invocable methods work as expected without actually making live callouts.
Launch Your Salesforce Career with Expert Training in Australia
Take your career to new heights with professional Salesforce training in Australia from CRS Info Solutions. Designed to equip you with the skills needed to thrive in the fast-growing Salesforce ecosystem, our courses focus on practical learning with real-time project experience. From Salesforce Admin and Developer to cutting-edge AI modules, we cover it all with hands-on training led by industry experts.
Whether you’re a beginner exploring the Salesforce training in Australia or an experienced professional looking to upgrade your skills, our training is tailored to meet your career goals. With personalized support, in-depth course materials, and expert guidance for certification and interview preparation, you’ll be fully prepared to excel in the industry.
Join us today for a free demo session and take the first step towards a rewarding Salesforce career!!!
See Also : What are classes in Apex programming?
What is a Map class in Salesforce Apex? with examples