Reputation: 11
I've been trying to figure out the test class for a web service callout. I have the four different classes. API_Member
which has all the parameters with all the information and matching of the fields. I have a API_Response
class and I've got an AccountTrigger
and AccountTriggerHandler
.
In the AccountTriggerHandler
, the whole HTTPRequest and callout is handled where I call the API_Member
class as well and then triggers it from the AccountTrigger
.
Now the difficulty is the test class since I'm not an experienced developer.
How would I manage to handle the test class for this code (I've made changes in case it's some important information)?
public with sharing class AccountTriggerHandler {
public void isAfterInsert(list<Account> accountNew) {
for(Account a: accountNew) {
sendData(a.Id);
}
}
public void isAfterUpdate(list<Account> accountNew) {
}
@future(callout=true)
public static void sendData(string accountId) {
API_Member api = new API_Member(accountId);
api.setupData();
API_Member.Data data = api.dataList;
string json = JSON.serialize(data);
system.debug('JSON' + json);
Http http = new Http();
HttpRequest request = new HttpRequest();
string url = 'http://api.XXXXXXXXXXXXXXXXXXXXXXX';
string username = 'Ext-XXXXXXXXXXXXXXX-XXXXXXXXXXXXXX';
string password = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
request.setHeader('Authorization', authorizationHeader);
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
request.setEndpoint(url);
request.setMethod('POST');
request.setBody(json);
HttpResponse response = http.send(request);
if (response.getStatusCode() == 201 || response.getStatusCode() == 200 ) {
API_Response responseCTRL = (API_Response) System.JSON.deserialize(response.getBody(), API_Response.class);
list<API_Response.Meta> m = responseCTRL.Meta;
System.debug('recordID='+m[0].recordID);
api.setResponse(m[0].recordID,response.getStatus());
}
}
}
Here is the API_Member Class
public class API_Member {
public Data dataList;
public Account input;
public Contact c;
public class Data {
public list<Info> data;
}
public class Info {
public String active;
public String address_city;
public String address_country;
public String address_line_1;
public String address_line_2;
public String address_state;
public String address_zipcode;
public String company_name;
public String date_end;
public String date_paid;
public String date_start;
public String email;
public String membership_number;
public String mobile;
public String org_number;
public String person_first_name;
public String person_last_name;
public String person_number;
public String phone;
public String status;
public String web_address;
}
public API_Member(string accountId) {
this.input = getAccount(accountId);
this.c = getContact();
}
public void setupData(){
dataList = new Data();
Info data = new Info();
data.active = 'true'; //To be verified
data.address_city = input.Ort__c;
data.address_country = '';
data.address_line_1 = input.Adress1__c;
data.address_line_2 = '';
//data.address_state = input.L_n_Namn__c;
data.address_zipcode = input.Postnummer__c;
data.company_name = input.Name;
data.date_end = input.Expiry_Date__c != null ? string.valueOf(input.Expiry_Date__c) : '';
data.date_paid = input.Last_Renew__c != null ? string.valueOf(input.Last_Renew__c) : '';
data.date_start = input.Last_Renew__c != null ? string.valueOf(input.Last_Renew__c): '';
data.email = input.Medlems_Epost__c;
data.membership_number = input.AccountNumber;
data.mobile = input.Phone;
data.org_number = input.Organisationsnummer__c;
data.person_first_name = c != null ? c.FirstName : '';
data.person_last_name = c != null ? c.LastName : '';
data.person_number = c != null ? c.Personnummer__c : '';
data.phone = input.Phone;
data.status = input.Status_Pay__c;
data.web_address = input.Website;
dataList.data = new list<Info>{data};
}
public Contact getContact(){
list<Contact> c = [ SELECT Id,
Personnummer__c,
LastName,
FirstName
FROM Contact
WHERE AccountId =: input.Id
ORDER BY CreatedDate
ASC
LIMIT 1
];
if(c.size() > 0){
return c[0];
}
return null;
}
public Account getAccount(string accountId){
Account a = [SELECT Id,
Ort__c,
Adress1__c,
Postnummer__c,
Name,
Expiry_Date__c,
Last_Renew__c,
Medlems_Epost__c,
AccountNumber,
Phone,
Organisationsnummer__c,
Status_Pay__c,
F_RecordId__c,
F_Satus__c,
Website
FROM Account
WHERE Id =: accountId
LIMIT 1
];
return a;
}
public void setResponse(string recordId, string Status) {
input.F_RecordId__c = recordId;
input.F_Satus__c = status;
update input;
}
}
Here is the API_Response Class
public class API_Response {
public class Meta {
public String recordID {get;set;}
public String href {get;set;}
}
public List<Meta> meta {get;set;}
public List<Data> data {get;set;}
public Info info {get;set;}
public List<MetaField> metaField {get;set;}
public class MetaField {
public String name {get;set;}
public Integer autoEntered {get;set;}
public Integer global_Z {get;set;} // in json: global
public Integer maxRepeat {get;set;}
public String resultType {get;set;}
}
public class Data {
public String address_city {get;set;}
public String address_country {get;set;}
public String address_line_1 {get;set;}
public String address_line_2 {get;set;}
public String address_state {get;set;}
public String address_zipcode {get;set;}
public String company_name {get;set;}
public String date_end {get;set;}
public String date_start {get;set;}
public String email {get;set;}
public String membership_number {get;set;}
public String mobile {get;set;}
public String org_number {get;set;}
public String person_first_name {get;set;}
public String person_last_name {get;set;}
public String person_number {get;set;}
public String phone {get;set;}
public String status {get;set;}
public String upload_data_status {get;set;}
public String web_address {get;set;}
}
public class Info {
public String X_RESTfm_Version {get;set;} // in json: X-RESTfm-Version
public String X_RESTfm_Protocol {get;set;} // in json: X-RESTfm-Protocol
public Integer X_RESTfm_Status {get;set;} // in json: X-RESTfm-Status
public String X_RESTfm_Reason {get;set;} // in json: X-RESTfm-Reason
public String X_RESTfm_Method {get;set;} // in json: X-RESTfm-Method
public String X_RESTfm_PHP_memory_limit {get;set;} // in json: X-RESTfm-PHP-memory_limit
public String X_RESTfm_PHP_post_max_size {get;set;} // in json: X-RESTfm-PHP-post_max_size
}
}
Upvotes: 1
Views: 7903
Reputation: 19612
For the unit test you will have to mock (fake) the service you're calling. We can't call real services from unit tests because:
You need to write a piece of code that will pretend it is that service. It's up to you how awesome it'll be. It can always return same message. Or it can inspect the data it received and throw error if required field is missing. Really - you decide, you know best how many scenarios you should test (how do you handle errors returned?)
The whole concept of mocking can be used for "normal" apex too, not just for callouts. Might be bit advanced topic though: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_stub_api.htm
Edit:
You'd need 2 classes you can mark as @isTest
(so they don't count towards your normal max of code). This is REST API, right? Not SOAP? Maybe https://trailhead.salesforce.com/content/learn/modules/apex_integration_services/apex_integration_rest_callouts would be better. In a pinch you could make it as 1 class but it's bit messy, keep them separate?
First make the API_ResponseMock
. It doesn't have to be global
, public
should be enough. Something like
@isTest
public class API_ResponseMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest request) {
// Create a fake response
HttpResponse response = new HttpResponse();
response.setHeader('Content-Type', 'application/json');
response.setBody('if you have sample JSON document that the service would return - paste it here. You must have something you used as the JSON2Apex input?');
response.setStatusCode(200);
return response;
}
This is base, you probably don't want it to return same content on every "callout" but good enough.
And AccountTriggerHandlerTest
would be "normal" unit test, with creation of test account. Something like
@isTest
static void testCallout() {
// Set mock callout class
Test.setMock(HttpCalloutMock.class, new API_ResponseMock());
Test.startTest();
insert new Account(Name = 'unit test'); // put whatever required fields you have
Test.stopTest(); // @future's don't run until this line.
// hm, what now? You have anything to "assert"? Will this callout be updating account maybe? Setting a Task with status=Completed, anything you can check?
}
Upvotes: 1