[SalesForce] How to write a test class for a class containing Web service callouts in salesforce

I am new to test classes in salesforce.
I want to write test class for an apex class which has Web service callouts.

My Apex code is :

public without sharing class UserConnect {
    public string myAPIKey{get; set;}
    public User currentUser;
    public Integer status{get; set;}

    public UserConnect(){
        currentUser = [SELECT Id,my_API_Key__c FROM User WHERE Id = :UserInfo.getUserId()];
        myAPIKey = currentUser.my_API_Key__c;
        status = 0;
    }


    public void saveMyAPIKey(){
        System.debug('calling saveMyAPIKey.........');
        System.debug(myAPIKey);
        if(myAPIKey != ''){
            status = testConnection();
            if(status == 200){
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.CONFIRM, 'Successful Connection'));   
            }
            else {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Connection Failed : invalid API key')); 
            }

            System.debug(currentUser);
            currentUser.my_API_Key__c = myAPIKey;
            Database.SaveResult SR = Database.update(currentUser);
        }
    }


    //check website connection
    private Integer testConnection(){   
        HttpRequest hReq = new HttpRequest();
        System.debug(myAPIKey);
        hReq.setEndpoint('https://www.webiste.com/data.json?auth_token='+myAPIKey);
        hReq.setMethod('GET');

        Http h = new Http();
        System.debug(hReq);
        HttpResponse hResp = h.send(hReq);  

        return hResp.getStatusCode();
    }
}

The Test Class for the above apex class is :

@isTest
public with sharing class UserConnect_TestClass {

     static testMethod void myTest() {
        string apiKey = 'here_apiKey';

        UserConnect class_test = new UserConnect();

        // Checking whether my-API-key is equal to the saved key...    
        System.assertEquals(class_test.myAPIKey, apiKey);

        class_test.status = 200;

        // Checking whether response status is equal to the 200 or not...
        class_test.saveMyAPIKey();
        System.assertEquals(class_test.status,200);     
    }
}

This test class gives me code coverage 71%.
Code Coverage view of code

    public without sharing class UserConnect {
            public string myAPIKey{get; set;}
            public User currentUser;
            public Integer status{get; set;}

            public UserConnect(){
                currentUser = [SELECT Id,my_API_Key__c FROM User WHERE Id = :UserInfo.getUserId()];
                myAPIKey = currentUser.my_API_Key__c;
                status = 0;
            }


            public void saveMyAPIKey(){
                System.debug('calling saveMyAPIKey.........');
                System.debug(myAPIKey);
                if(myAPIKey != ''){
                    status = testConnection();
////////// Not covered code Start...
                    if(status == 200){
                        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.CONFIRM, 'Successful Connection'));   
                    }
                    else {
                        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Connection Failed : invalid API key')); 
                    }


                    currentUser.my_API_Key__c = myAPIKey;
                    Database.SaveResult SR = Database.update(currentUser);
/////// Not covered code end.......

                }
            }


            //check website connection
            private Integer testConnection(){   
                HttpRequest hReq = new HttpRequest();
                System.debug(myAPIKey);
                hReq.setEndpoint('https://www.webiste.com/data.json?auth_token='+myAPIKey);
                hReq.setMethod('GET');

                Http h = new Http();
                System.debug(hReq);
                HttpResponse hResp = h.send(hReq);  

/// Not Covered Code start....
                return hResp.getStatusCode();
/// Not Covered Code end....

            }
    }

And the failure message is : Methods defined as TestMethod do not support Web service callouts.

Note: The code coverage view contains the comments to show uncovered code.

Please correct my test class according to the error.
Any help will be appreciated…

Best Answer

To test a callout, you need to "mock" it.

You will need to create a private inner class (well, you don't need to do it like that, but I find it easier) along the lines of:

private class GetAPIKeyMock implements HttpCalloutMock {
    private Integer returnedStatusCode;

    public GetAPIKeyMock(Integer returnedStatusCode) {
        this.returnedStatusCode = returnedStatusCode;
    }

    public HTTPResponse respond(HTTPRequest req) {
        // you can use System.assert here and "if" calls to check the request and affect your return if you wish

        HttpResponse res = new HttpResponse();
        res.setStatusCode(returnedStatusCode);
        return res;
    }
}

In this one, you tell it what status code you want to return in the "Mock" method, then when it is called, it will return a response with that value.. so you can use this to check your 200 case and your else..

Once you have this inner class, in your test class, you need to tell it to use the mock when the call out is called. So in your @isTest method add:

    Test.setMock(HttpCalloutMock.class, new GetAPIKeyMock(200));

This tells your test method to use the GetAPIKeyMock class, and to return a HTTP 200 when it responds.

Related Topic