Esempio di callout Apex

Questa callout è di tipo rest e chiama un endpoint per aggiornarnare l’inventario dei prodotti a disposizione di una società.

In questo esempio è utilizzata anche una wrapper class perchè il risultato della chiamata da campi che devono essere mappati con quelli dell’oggetto “prodotti” in Salesforce

public with sharing class WarehouseCalloutService {

    private static final String WAREHOUSE_URL = 'https://th-superbadge-apex.herokuapp.com/equipment';
    
    // complete this method to make the callout (using @future) to the
    // REST endpoint and update equipment on hand.
    @future(callout=true)
    public static void runWarehouseEquipmentSync(){ // questo dovrebbe girare dal trigger MaintenanceRequest. e utilizzare la lista dei case interessati List<Id> equip
        
        Http h = new Http();
        
        HttpRequest rq = new HttpRequest();
        rq.setEndpoint(WAREHOUSE_URL);
        rq.setMethod('GET');        
        rq.setCompressed(true);
        
        
            HttpResponse res = h.send(rq);
            
            List<Product2> listaprodotti = new List<Product2>();
            
            if(res.getStatusCode() == 200){
             List<Json2Apex> lstOfEquipments = (List<Json2Apex>) JSON.deserialize(res.getBody(), List<Json2Apex>.class);
             for(Json2Apex inst:lstOfEquipments){
                 Product2 prod = new Product2();
                 prod.Cost__c = inst.cost;
                 prod.Lifespan_Months__c = inst.lifespan;
                 prod.Maintenance_Cycle__c = inst.maintenanceperiod;
                 prod.Name = inst.name;
                 prod.Current_Inventory__c = inst.quantity;
                 prod.Replacement_Part__c = inst.replacement;
                 prod.Warehouse_SKU__c = inst.sku;
                 
                 listaprodotti.add(prod);
                 
             }
             
             if(listaprodotti != null && listaprodotti.size() > 0){
                 UPSERT listaprodotti Warehouse_SKU__c;
             }
             
            }else{
                System.debug('Errore di connessione al endpoint');
            }                       
        
    }
    
    // wrapper class
    private class Json2Apex{
        private String id;
        private Integer cost;
        private Integer lifespan;
        private Integer maintenanceperiod;
        private String name;
        private Integer quantity;
        private Boolean replacement;
        private String sku; 
    }

}

Testare una callout rest

Per testare una callout rest bisogna creare una classe mock e una classe di test

Iniziamo dalla classe mock

@isTest
global class WarehouseCalloutServiceMock implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest request) {
        // Create a fake response
        HttpResponse response = new HttpResponse();
        response.setHeader('Content-Type', 'application/json');
        response.setBody('[{"_id": "55d66226726b611100aaf741","replacement": false,"quantity": 5,"name": "Generator 1000 kW","maintenanceperiod": 365,"lifespan": 120,"cost": 5000,"sku": "100003"},{"_id": "55d66226726b611100aaf742","replacement": false,"quantity": 5,"name": "Cooling Fan","maintenanceperiod": 365,"lifespan": 120,"cost": 5000,"sku": "100004"}]');
        response.setStatusCode(200);
        return response; 
    }
}

La classe mock simula la chiamata all’esterno

Mentre la classe di test invoca sia la mock si la callout da testare

@isTest
private class WarehouseCalloutServiceTest {
    
    
    @isTest static  void testGetCallout() {
        
        Test.setMock(HttpCalloutMock.class, new WarehouseCalloutServiceMock());
        
        Test.startTest();
      		WarehouseCalloutService.runWarehouseEquipmentSync(); 
    	Test.stopTest();
        
        Product2 p = [select Name from product2 where Warehouse_SKU__c = '100003' ];        
        System.assertEquals(p.name, 'Generator 1000 kW');
        
    }
    
    
}

Esempio da documentazione ufficiale

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_wsdl2apex_testing.htm

Classe Mock che implementa diverse interfacce

@isTest
global class DiscardCalloutMock implements WebServiceMock {


    global void doInvoke(
           Object stub,
           Object request,
           Map<String, Object> response,
           String endpoint,
           String soapAction,
           String requestName,
           String responseNS,
           String responseName,
           String responseType) {

        // Create response element from the autogenerated class.
        // Populate response element.
        // Add response element to the response parameter, as follows:
        response.put('response_x', getResponseKO()); 
   }

    

    public static [Tipo] getResponseKO(){
        [Tipo] calloutResponse = new [Tipo]();

        wrts_prcgvr.MRR_1_0.Response response = new wrts_prcgvr.MRR_1_0.Response();
        response.code = 'KO';
        response.description = 'Case Transition not found AsyncResponse Current Phase :AL010';
        response.header = new [Tipo]();        
        response.header.fields = new List<[Tipo]>{
            buildField('flowCode', 'string', 'A01_0150'),
            buildField('status', 'string', '0'),
            buildField('category', 'string', 'AsyncResponse')
        };

        response.header.requestId = 'AGIwXHMf51tba6bmjMVMcHRb7-gS';
        response.header.requestTimestamp = '2022-03-15 17:59:41';
        response.header.requestType = 'Richiesta Aggiornamento Case';
        
        
        List<wrts_prcgvr.MRR_1_0.Response> rList = new List<wrts_prcgvr.MRR_1_0.Response>();
        rList.add(response);
        calloutResponse.responses = rList;        
        return calloutResponse;
    }

    public static [Tipo](String name, String type, String value){
        [Tipo] = new [Tipo].Field();
        field.name = name;
        field.fieldType = type;
        field.value = value;
        return field;
    }
}