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='[email protected]';
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()
andTest.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:
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