-3

This is my apex class, please help me in writing a test class for it.Thanks

global clas LoginClass{

public string Cookie_M;
public string Session_M;
public string Token_M;
public string Username_M; 
public string Password_M;
public string URL_M; 
public string Name_M;    
public String StatusResp;
Http httpToken = new Http();
HttpRequest reqToken =  new HttpRequest(); 
public HttpResponse resToken =  new HttpResponse();
Http http = new Http();
HttpRequest req =  new HttpRequest();  
HttpResponse res =  new HttpResponse();  
public Dom.Document doc;
// Login Access   
public String getLoginAccess(String Name, String username, String password, String url){

    Name_M  = Name; 
    Username_M = username;
    Password_M = password;
    URL_M = url;
    system.debug(username);system.debug(url);
    Blob headerValue = Blob.valueOf(username + ':' + password);
    String authorizationHeader = 'BASIC ' +EncodingUtil.base64Encode(headerValue);

    //Token Request 

    reqToken.setHeader('Authorization', authorizationHeader);              
    reqToken.setEndpoint(url+'/api/xml?action=login&login='+username+'&password='+password);                      
    reqToken.setMethod('GET');
    reqToken.setHeader('Content-Type', 'application/json');
    reqToken.setHeader('Accept','application/json'); 


    try{ 
        resToken = httpToken.send(reqToken); 
        if(resToken !=null){
        System.debug('Result :: '+resToken.getBody());
        System.debug('*Resp :: ' + String.ValueOF(resToken.getBody()));
        System.debug('RESPONSE STRING :: ' + resToken.toString());
        System.debug('RESPONSE STATUS: ' + resToken.getStatus());
        System.debug('STATUS_CODE: ' + resToken.getStatusCode());         
        System.debug('Cookie :: '+resToken.getHeader('Set-Cookie'));
        System.debug('Session :: '+resToken.getHeader('Set-Cookie').substringBetween('BREEZESESSION=', ';'));       

        //get token from XML response           
        doc = resToken.getBodyDocument();              
        Dom.XMLNode results = doc.getRootElement();
        Dom.XMLNode common = results.getChildElement('OWASP_CSRF_TOKEN', null); 
        Dom.XMLNode Status = results.getChildElement('status', null); 
        if(resToken!=null){
        Session_M = resToken.getHeader('Set-Cookie').substringBetween('BREEZESESSION=', ';'); //This is not cookie this is session  
        System.debug('session :: '+Session_M);            
        }
        if(common != Null) {                  
            Token_M = common.getChildElement('token', null).getText();
            System.debug('*** Access Token *** :: ' +Token_M);            
            System.debug('*** Access Token length *** :: ' +Token_M.length() + ' string :: ' +String.valueof(Token_M.length()));                  
        }               

        StatusResp = Status.getAttributeValue('code',null);
        System.debug('StatusResp :: ' +StatusResp);
       }
    }catch(System.CalloutException e) {
        System.debug('Server Callout Exception in response for Token :: ' + e.getMessage());
        StatusResp = e.getMessage() ;
        System.debug('StatusResp :: ' +StatusResp);
    }  
    catch(Exception e) {
        System.debug('Exception in response for API call :: ' + e.getMessage());
        StatusResp = e.getMessage() ;
        System.debug('StatusResp :: ' +StatusResp);
    }    

       System.debug('StatusResponse :: ' +StatusResp);

    //Cookie Request              
    HttpRequest requestCookie = new HttpRequest();     
    requestCookie.setHeader('Authorization', authorizationHeader);                  
    requestCookie.setEndpoint(url+'/api/xml?action=login&login='+username+'&password='+password+'&domain=apac1cps.adobeconnect.com&session='+Session_M);      
    requestCookie.setHeader('Content-Type', 'application/json');
    requestCookie.setHeader('Accept','application/json'); 

    requestCookie.setMethod('POST');

    Http httpCookie = new Http();       
    HttpResponse responseCookie = new HttpResponse();


    try {
            responseCookie = httpCookie.send(requestCookie);
            System.debug('*Resp Cookie:' + String.ValueOF(responseCookie.getBody()));
            System.debug('RESPONSECookie STRING: ' + responseCookie.toString());
            System.debug('RESPONSECookie STATUS: ' + responseCookie.getStatus());
            System.debug('STATUS_CODE: ' + responseCookie.getStatusCode());         


    System.debug('*** Cookie *** :: '  +responseCookie.getBody());                        
   /* string location = responseCookie.getHeader('Location');            
    System.debug('*** Cookie Location *** :: '  + location); */                                
    Cookie_M = responseCookie.getHeader('Set-Cookie');
    System.debug('cookie is : ' +  Cookie_M );

    if((!StatusResp.contains('Unauthorized endpoint,'))){
        if((!StatusResp.contains('no-data'))){
            if((!StatusResp.contains('invalid'))){
                GetEventList();
                XMLLoginAccess loginaccess = new XMLLoginAccess(Name_M,Username_M,Password_M,URL_M,Session_M,Token_M);   
            }
        }
    }
    }             
        catch(System.CalloutException e) {
            system.debug('Server Callout Exception in responseCookie :: ' + e.getMessage());
        } catch(Exception e){
            system.debug('Other exception ::'+e.getMessage());
        }
     System.debug('StatusResponsesss :: ' +StatusResp);                                 

    return StatusResp;

}

//
public void GetEventList(){

    Blob headerValue = Blob.valueOf(Username_M + ':' + Password_M);
    String authorizationHeader = 'BASIC ' +EncodingUtil.base64Encode(headerValue);


    req.setHeader('Authorization', authorizationHeader);  
    req.setEndpoint(URL_M+'/api/xml?action=report-my-events&session='+Session_M);
    req.setMethod('GET');
    req.setHeader('Content-Type', 'application/json');
    req.setHeader('Accept','application/json');
    req.setHeader('Cookie', Cookie_M);
    try {
        res = http.send(req); 
        System.debug('MyResult :'+res.getBody());            
        // Saves these webinar records in SF
        XMLParserCopy s = new XMLParserCopy(res.getBody());
        System.debug('Response value'+s);   

    }catch(System.CalloutException e){
           System.debug('Callout error: '+ e);              
     }

}
2
  • 1
    There is a quality introduction to testing on Trailhead, as well as a three-part series on the Salesforce Developer Blog to introduce you to the principles and techniques. SFSE can support you when you encounter a specific issue, but isn't able to write test classes for you.
    – David Reed
    Commented Aug 9, 2018 at 18:09
  • 1
    You'll definitely also want to look at using mocks to test callouts.
    – David Reed
    Commented Aug 9, 2018 at 18:11

1 Answer 1

1

This seems to be a common problem when testing callouts, especially when multiple callouts to different endpoints are made from a single method.

sfdxfox posted the original EchoHttpMock (I believe) which moved the logic for what to return into the test method that was running which reduced the need for complex response classes.

I took it one step further and added the ability to set the responses returned based on the a default response for no matches, matched endpoint, or even match body content.

This allowed for precise control within the test method of what is returned and only requires one class to handle the mock for all test code.

Note The below is based on my need by can be adapted to your question as well

EchoHttpMock Class

@IsTest
public class EchoHttpMock implements HttpCalloutMock {

    /**@description The response to return */
    HttpResponse res;
    /**@description A map of responses to return based either on the endpoint or request body contents */
    Map<String, HttpResponse> responseByEndpointOrContent;

    /***************************************************
    * @description Constructor
    * @param HttpResponse The HttpResponse to return if the mapped responses is null or finds no match
    * @param Map<String,HttpResponse> The map of responses to return with either the endpoint or response body part as the keys
    ****************************************************/
    public EchoHttpMock(HttpResponse r, Map<String, HttpResponse> responseByEndpointOrContent) {
        res = r;
        this.responseByEndpointOrContent = responseByEndpointOrContent;
    }

    /***************************************************
    * @description HttpCalloutMock Interface method to return the response
    * @param HttpRequest The request
    * @return HttpResponse The Response
    ****************************************************/
    public HttpResponse respond(HttpRequest req) {

        if (responseByEndpointOrContent == null) {
            return res;
        }
        else {
            //The if and for can be reordered to fit your needs based on what you want to match on first
            if (responseByEndpointOrContent.containsKey(req.getEndpoint())) {
                return responseByEndpointOrContent.get(req.getEndpoint());
            }

            for (String bodyPart : responseByEndpointOrContent.keySet()) {
                if (req.getBody() != null && req.getBody().containsIgnoreCase(bodyPart)) {
                    return responseByEndpointOrContent.get(bodyPart);
                }
            }

        }
        //No matches, just return the default response (First 3 params of the EchoHttpMock constructor
        return res;
    }

    /***************************************************
    * @description Set the Mock to return basic response with the specified parameters
    * @param Integer Response Status Code
    * @param String Response Status
    * @param String Response Body
    * @return Void
    ****************************************************/
    public static void setTestMockResponse(Integer statusCode, String status, String body) {
        setTestMockResponse(statusCode, status, body, null);
    }

    /***************************************************
    * @description Set the Mock to return basic response OR a constructed response based on the mapped endpoint or request body content
    * @param Integer Response Status Code
    * @param String Response Status
    * @param String Response Body
    * @param Map<String,HttpResponse> Map of responses to return with either the endpoint or request body part as the key
    * @return Void
    ****************************************************/
    public static void setTestMockResponse(Integer statusCode, String status, String body, Map<String, HttpResponse> responseByEndpointOrContent) {
        HttpResponse mockResp = new HttpResponse();

        if (statusCode != null) {
            mockResp.setStatusCode(statusCode);
        }

        if (status != null) {
            mockResp.setStatus(status);
        }

        if (body != null) {
            mockResp.setBody(body);
        }

        test.setMock(
                HttpCalloutMock.class,
                new EchoHttpMock(mockResp, responseByEndpointOrContent)
        );

    }
}

Example Usages to call in your test class:

  1. Basic response for any callout made during the test method

    EchoHttpMock.setTestMockResponse(200,'OK',YOURRESPONSEBODY);
    
  2. Response by content or endpoint with a default no match response

    //Returns 404 if no matched content. If body contains assertion or the endpoint is https://www.google.com return the defined httpresponse
    
    HttpResponse refreshResponse = new HttpResponse();
    refreshResponse.setStatusCode(200);
    refreshResponse.setBody(YOURBODYHERE);
    
    
    Map<String, HttpResponse> responseByBodyContent = new Map<String, HttpResponse>{
            'assertion' => refreshResponse, //Body contains assertion
            'https://www.google.com' => refreshResponse //Endpoint match
    };
    
    EchoHttpMock.setTestMockResponse(404, 'Not Authorized', null, responseByBodyContent);
    

The above are just two use cases. But you can use the one EchoMock class to handle all your callouts during tests. Additionally if your multiple calls are to the same endpoint, you can match on the request body to differentiate.

1
  • Thanks @Eric, It's worked for me. I could make a multiple Callouts with the HttpCalloutmock interface and I'm getting 79% of code coverage for my apex class. Here, is a small issue got found. I can't get the inner methods code coverage in the class. The Dom.Document which takes the response from a callout, can it be tested in the same class?
    – mira
    Commented Aug 10, 2018 at 19:29

Not the answer you're looking for? Browse other questions tagged .