1

I have the following trigger and REST-callout class in a source org:

trigger SendOpp_Trigger on Opportunity (before insert) {
    for(Opportunity o : Trigger.new){
        SendOpportunity.createOpportunity(o.name, o.Account_External_Id__c, o.CloseDate, o.StageName);
    }
}


public class SendOpportunity {

    String clientId = '*****';
    String clientsecret ='*****';
    String username='fake@fake.com';
    String password = '*****';
    String accesstoken_url = 'https://login.salesforce.com/services/oauth2/token';
    String authurl = 'https://login.salesforce.com/services/oauth2/authorize';

    public class deserializeResponse {

        public String id;
        public String access_token;

    }

    public String ReturnAccessToken(SendOpportunity Opp){

        String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='
        +clientSecret+'&username='+username+'&password='+password;

        Http h= new Http();
        HttpRequest req= new HttpRequest();
        req.setBody(reqbody);
        req.setMethod('POST'); 
        req.setEndpoint('https://na50.salesforce.com/services/oauth2/token');

        HttpResponse res=h.send(req);

        deserializeResponse resp1= (deserializeResponse)JSON.deserialize(res.getBody(),deserializeResponse.class);

        return resp1.access_token;
    }

    @future(callout=true)
    public static void createOpportunity(String oppName, String acctId, Date d, String stage){

        SendOpportunity opp1 = new SendOpportunity();

        String accessToken = opp1.ReturnAccessToken(opp1);

        if(accessToken!=null){

            String endPoint='https://na50.salesforce.com/services/data/v42.0/sobjects/Opportunity';             

            String jsonstr='{"Name":"'+ oppName +'","AccountId":"'+ acctId +'","CloseDate":"'+ String.valueOf(d) +'","StageName":"'+ stage +'"}';

            Http h2 = new Http();
            HttpRequest req2 = new HttpRequest();
            req2.setHeader('Authorization','Bearer ' + accessToken);
            req2.setHeader('Content-Type','application/json');
            req2.setHeader('accept','application/json');
            req2.setBody(jsonstr);
            req2.setMethod('POST');
            req2.setEndpoint(endPoint);

            HttpResponse res2 = h2.send(req2);

            system.debug(res2.getBody());

            deserializeResponse deresp=(deserializeResponse)System.JSON.deserialize(res2.getBody(),deserializeResponse.class);
        }
    }
}

Here's the mock:

@isTest
global class SendOpportunityMock 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('{"Name":"Test Opp Name","AccountId":"123456789123456789","CloseDate":"2018-02-28 00:00:00","StageName":"Prospecting"}');
        response.setStatusCode(200);
        return response; 
    }
}

Finally, the following is the test I have so far. Included is commented-out code that would work if the future callout method - createOpportunity - could be given a return type. However, future methods do not support return types:

@isTest
private class SendOpportunityTest {    

    @isTest static void testPostCallout() {

        Date d = date.valueOf('2017-12-13T12:38:43.000Z');        

        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new SendOpportunityMock()); 
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock.
        Account a = new Account(Name = 'Test Account Name', External_Id__c = '123456789123456789');
        insert a;
        Opportunity o = new Opportunity(Name = 'Test Opp Name', AccountId = a.Id, CloseDate = d, StageName = 'Prospecting');        
        insert o;
        Test.starttest();
        SendOpportunity.createOpportunity('Test Opp Name', '123456789123456789', d, 'Prospecting');
        Test.stoptest();

 /*     HttpResponse response = SendOpportunity.createOpportunity();
        // Verify that the response received contains fake values
        String contentType = response.getHeader('Content-Type');
        System.assert(contentType == 'application/json');
        String actualValue = response.getBody();
        System.debug(response.getBody());
        String expectedValue = '{"Name":"Test Opp Name","AccountId":"123456789123456789","CloseDate":"2017-12-13T12:38:43.000Z","StageName":"Prospecting"}';
        System.assertEquals(actualValue, expectedValue);
        System.assertEquals(200, response.getStatusCode());  */
    }
}

A couple of additional details about my test so far:

  • I tried Test.starttest() and Test.stoptest() because I read elsewhere that they could possibly be the solution. But they don't solve the problem, at least not on their own.
  • My trigger calls the createOpportunity method when an opportunity is created, so I inserted an opportunity - in addition to directly calling the method - just to cover the trigger.

I only achieve 63% coverage on the class when I run the test. The pink lines in the screenshot below are the only ones that aren't covered:

enter image description here

Since the commented-out code in my test is the only variation I know and can find for testing REST callouts, I don't know how to proceed to achieve 100% coverage.

Any ideas?

Thanks

2

I think issue is ReturnAccessToken method is also using callout, so you need to mock that callout.

After you mock that, then accessToken should not be null and hence you will get rest of code coverages.

Otherwise, you need to use this kind of logic in createOpportunity method.

if(Test.isRunningTest()){
    accessToken = 'Define your token';
}
if(accessToken!=null){

    //your existing webservice code.
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.