function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Suman KuchSuman Kuch 

Testing Visualforce cotrollers with HTTP callouts help

Hi,
I'm new in development and working on uploading Attachments to external storage "Box" using REST API calls. I wrote Apex code for uploading files but stuck on writing Unit Test on visualforce controllers that has Http callouts. Please give me clue on how to write test for this, here is the Apex code.
 
global class GUBoxController {
    
    // Custom Controller
  
    private static String fileID {get;set;}
   
    private static String uploadError {get;set;}
    global  String fileName {get;set;}
    global  Blob fileBody {get;set;}

  /*This function invokes when upload clicked on visualforce page and returns to Parent page ('recId') 
  global PageReference processUpload() {
        Id recId = ID.valueOf(ApexPages.CurrentPage().getparameters().get('recId'));
	    String objType=String.valueOf(recId.getSObjectType().getDescribe().getName());
        sObject sObj = Database.query('select Name from '+objType+' where ID=:recId');
        String objName = String.valueOf(sObj.get('Name'));
        createAttachment(objType, objName, fileName, fileBody, recId, fileType);
        if (uploadError !=null && uploadError.length() > 0){
        	return new PageReference('/apex/GUBoxController?recId='+recId);
        }else{
            return new PageReference('/'+recId);
        }
    }
    //@future (callout=true)
    public static void  createAttachment(String objTypeFolderName, String objFolderName, String boxFileName, 
                                         Blob boxFileBody, ID objID, String boxFileType){
        try{
            uploadFileToBox(boxFileName,boxFileBody,sObjectFolderID );
            saveCustomAttachment(objTypeFolderName, boxFileName,objID);
        }catch(Exception e){
            System.debug(' Box Exception '+e);
        }
    }
    //@Future(callout=true)
    public static void uploadFileToBox(String fileName, Blob fileBody,String parentFolderID) {
        try{
            String boundary = '----------------------------741e90d31eff';
            String header = '--'+boundary+'\nContent-Disposition: form-data; name="file"; filename="'+fileName+'";\nContent-Type: multipart/form-data;'+'\nnon-svg='+True;
            String footer = '--'+boundary+'--';             
            String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
            HttpResponse res;
            while(headerEncoded.endsWith('=')){
                header+=' ';
                headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
            }
            String bodyEncoded = EncodingUtil.base64Encode(fileBody);
            Blob bodyBlob = null;
            String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());

            if(last4Bytes.endsWith('==')) {
                    last4Bytes = last4Bytes.substring(0,2) + '0K';
                    bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
                    String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
                    bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
                }else if(last4Bytes.endsWith('=')){
                    last4Bytes = last4Bytes.substring(0,3) + 'N';
                    bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
                    footer = '\n' + footer;
                    String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
                    bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);              
                }else{
                    footer = '\r\n' + footer;
                    String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
                    bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);  
                }
            String sUrl = 'https://upload.box.com/api/2.0/files/content?parent_id='+parentFolderID;
            HttpRequest req = new HttpRequest();
            req.setEndpoint(sUrl);
            req.setMethod('POST');
            req.setBodyAsBlob(bodyBlob);
            req.setHeader('Content-Type','multipart/form-data;non_svg='+True+';boundary='+boundary);
            req.setTimeout(20000);
            req.setHeader('Content-Length',String.valueof(req.getBodyAsBlob().size()));
            Http http = new Http();
            system.debug('HttpRequest details '+req);
            res = http.send(req);
            system.debug('.......Response........'+res);
            if (res.getStatus() == 'Conflict'){
                
            }
            JSONParser parser = JSON.createParser(res.getBody());
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && 
                    (parser.getText() == 'id')) {
                        parser.nextToken();
                        fileID=parser.getText();
                        break;
                    }
            }
        }catch(Exception e){
            if (e.getMessage().contains('Exceeded max size limit of 6000000')){
                uploadError=' Exceeded the max file size limit, reduce the size to below 5MB ';
            }
        }
    }
}

 
Pankaj MehraPankaj Mehra
Hi Suman, 

You need to create a HTTP Mock class where you will create a dummy response, mention the mock class in your test class and you are good to go

Mock class will look like :
@isTest
global class MockHttpResponseGenerator implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest req) {
        // Optionally, only send a mock response for a specific endpoint
        // and method.
        System.assertEquals('http://api.salesforce.com/foo/bar', req.getEndpoint());
        System.assertEquals('GET', req.getMethod());
        
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody('{"foo":"bar"}');
        res.setStatusCode(200);
        return res;
    }
}


Now that you have specified the values of the fake response, instruct the Apex runtime to send this fake response by calling Test.setMock in your test method. For the first argument, pass HttpCalloutMock.class, and for the second argument, pass a new instance of your interface implementation of HttpCalloutMock, as follows:
 
Test.setMock(HttpCalloutMock.class, new ***YourHttpCalloutMockImpl***());
 Callout class
 
public class CalloutClass {
    public static HttpResponse getInfoFromExternalService() {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://api.salesforce.com/foo/bar');
        req.setMethod('GET');
        Http h = new Http();
        HttpResponse res = h.send(req);
        return res;
    }
}

Test Class
 
@isTest
private class CalloutClassTest {
     @isTest static void testCallout() {
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
        
        // Call method to test.
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        HttpResponse res = CalloutClass.getInfoFromExternalService();
        
        // Verify response received contains fake values
        String contentType = res.getHeader('Content-Type');
        System.assert(contentType == 'application/json');
        String actualValue = res.getBody();
        String expectedValue = '{"foo":"bar"}';
        System.assertEquals(actualValue, expectedValue);
        System.assertEquals(200, res.getStatusCode());
    }
}

Thanks




 
Suman KuchSuman Kuch
Thanks Pankaj for reply..
I got this information online when I googles but here I have two functions, one is "processUpload" which is visualforce controller and another one is "uploadFileToBox" which is callout method and this uploadFileToBox being invoked from processUpload function, so in this scenario how can I write test code? Please advice.
Pankaj MehraPankaj Mehra
Hi Suman, 

First you will need to get the output of the service processUpload and uploadFileToBox, you can get by firing the service and see developer console to get the response, then copy that response and paste in the mockup class 

res.setBody(RESPONSE_STRING);  

Then you are good with the test class.

Thanks

 
Suman KuchSuman Kuch
Hi Pankaj, I think this is going to help, Let me try this.