2

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...

1

1 Answer 1

3

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.

8
  • This is working for me :) But there is a small issue. The inner class that I have made in test class , is also included in code coverage and is zero percent covered. How can we solve this?? Commented Dec 29, 2015 at 12:52
  • if it is inside an inner class, then it doesn't require coverage.. if the developer console is complaining or giving you the impression it is badly covered then it is just because the developer console is a piece of crap! If you save all your files, close them all in the console and then run ALL tests, it should "clear out" the complaint (though sometimes it can take a day or two to realise that test classes don't need test coverage. It won't stop you deploying or packaging code. It is purely a reporting-to-user bug/problem with SFDC. Commented Dec 29, 2015 at 12:58
  • Yeah, I noticed it. I have run the test cases from Force.com IDE using eclipse, It didn't show me the inner class in code coverage. Commented Dec 29, 2015 at 13:02
  • Can you please give me a short summary about mock usage in this kind of problem. As my problem has been solved but how? I dont know :P Commented Dec 29, 2015 at 13:04
  • If you check the other answer.. the link to documentation explains MockCallouts nicely. developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… - But if you mean the problem regarding test coverage, it just takes salesforce a little while to work out the new code is in a test class... it's just a "bug" but it always resolves itself, and like I said, doesn't actually "block" anything - it just reports coverage wrong for a little while (2 minutes to 2 days). Commented Dec 29, 2015 at 13:08

You must log in to answer this question.

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