I need to cover my class code. I have http callouts in it. Any lead how to do that?
I've searched in the internet and found that httpcalloutmock help to test the http's request.
Any example please?!
My method callout is like this:
@future(callout=true)
public static void GetIdObject(set<string> listObjIds){
mapObj = DAL.getMapObjectsByIds(listObjIds);
List <Object__c> listObj = new List<Object__c>();
// if(!system.Test.isRunningTest()){
system.debug('*****************mapObjAvaya**************'+mapObj);
for(Object__c Obj : mapObj.values()){
if(Obj.Id !=null ){
callWSGetIdObject(Obj);
listObj.add(Obj); //listObj
}
}
update listObj; //listObj
// }
}
public static void callWSGetIdObject(Object__c Obj ){
PAD.myLog('Calling the web service callWSGetIdObject');
String agent;
String BDValues;
String UserId = UserInfo.getUserId();
HttpRequest req = new HttpRequest();
HTTPResponse res = new HTTPResponse();
User user= [select Id, CRC__c, Alias, Type_Interne_Externe__c from User where Id=:UserId ];
// if(!system.Test.isRunningTest()){
PAD.myLog('##### Map Object ID WS Nice Bridge ______'+mapObj);
agent = user.Alias;
BDValues ='S-'+Obj.Id;
PAD.MyLog('USER CRC '+ user.CRC__c);
if (user.CRC__c=='CRC'){
//isReqValid= true;
String url = Label.url+ Label.CodeSwitch+
+ '&Agent=' + EncodingUtil.urlEncode(agent,'UTF-8')
+ '&BDNames=' + EncodingUtil.urlEncode(Label.BDNames,'UTF-8')
+ '&BDValues=' + EncodingUtil.urlEncode(BDValues,'UTF-8')
+ Label.Overwrite;
PAD.myLog(url);
// Add the endpoint to the request
req.setEndpoint(url);
req.setMethod('GET');
Http http = new Http();
try {
if(!system.Test.isRunningTest()){
res = http.send(req);
}
PAD.myLog('##### CALLOUT RESULT _____ '+res);
PAD.myLog('##### CALLOUT RESPONSE _____ '+res.getBody());
}
catch(System.CalloutException e) {
PAD.myLog('????Error in HttpRequest Callout' + res.toString());
PAD.myLog('###Exception :'+e.getTypeName()+' :' +e.getMessage());
}
// create the xml doc that will contain the results of the Callout operation
Dom.Document doc = new Dom.Document();
try{
XmlStreamReader reader = res.getXmlStreamReader();
system.debug('#### XML READER ________ '+reader);
doc.load(res.getbody());
Dom.XMLNode root = doc.getRootElement();
PAD.myLog('ROOT '+root);
// Get the first child element of the root
Dom.XMLNode data= root.getChildElements()[0];
// Get the second chile element of the root => Result element
Dom.XMLNode result= root.getChildElements()[1];
PAD.myLog('RESULT '+RESULT);
// Get the childs of 'Result' Element
for(Dom.XMLNode child :root.getChildElements()){
if(child.getName() == 'Result'){
Obj.Status__c = child.getChildElements()[0].getText();
Obj.Message__c = child.getChildElements()[1].getText();
Obj.Status_Ex__c = child.getChildElements()[2].getText();
PAD.myLog('STATUS '+child.getChildElements()[0].getText());
PAD.myLog('MESSAGE '+child.getChildElements()[1].getText());
PAD.myLog('STATUS EXTENDED '+child.getChildElements()[2].getText());
}
}
}
// catching exception while invalid XML
catch (System.XMLException e) {
//isReqValid = false;
//LstObjToUpdate.add(Obj);
PAD.myLog(e.getMessage());
}
}
//}
//system.debug('### ISREQVALID '+isReqValid);
/*if (isReqValid && !system.Test.isRunningTest())
checkWsSuccessGetIdObject(res, Obj);*/
}
My httpresponsegenerator Mock
@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('URL'
+ '&Agent=Momo'
+ '&BDNames=LDE_Name'
+ '&BDValues=LDE_Value'
+ '&Overwrite=-1', req.getEndpoint());
System.assertEquals('GET', req.getMethod());
// Create a fake response
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'text/xml');
String body='<Output xmlns=\"nice.uniform://\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Data i:nil="true"/><Result xmlns:a=\"http://nice"><a:ResultCode>RESULTCODE</a:ResultCode><a:ResultMessage>No open call exists</a:ResultMessage><a:ResultCodeEx>CLS_SE_NO_OPEN_CALL</a:ResultCodeEx></Result><Exception i:nil="true" xmlns:a="http://schemas.datacontract.org/2004/07/System"/></Output>';
res.setBody(body);
res.setStatusCode(200);
Dom.Document doc = new Dom.Document();
doc.load(body);
return res;
}
}
My UnitTest:
static testMethod void myUnitTestIdObj() {
Profile p = [select id from profile where Name='Administrateur système' limit 1];
User CurrentUser = TestCommon.createUser('trinity', '@test.sfd.test', 'MyTestLastName2','MyTestFirstName2',p.Id,'CRC');
System.runAs(CurrentUser )
{
Product2 prod = new Product2(family = 'AAF', name = 'test', FMES__c = 0, Isactive = true);
insert prod;
Account acc = new Account(NClientLDE__c = '456', name = 'test', origine__c = 'Epsydre');
insert acc;
Object__c Obj = new Object__c(produit__c = prod.id, DatedeObject__c= Date.today(), client__c = acc.id, Motifresiliation__c = label.Venteforcee);
insert Obj;
Obj.produit__c = prod.id;
update Obj;
Set<string> devNotExecute=new Set<String>();
devNotExecute.add('TR007ManageWSIEM');
PAD.doNotExecuteAfterMe(devNotExecute);
System.assert(Obj.id!=null);
set<string> ObjIds = new set<string>();
ObjIds.add(Obj.id);
// Tests DAL
Account a = DAL.getAccountById(acc.Id);
a = DAL.getAccountByNumLDE('456');
User u = DAL.getUserById('userId');
Object__c s = DAL.getObjectById(Obj.Id);
String agent = 'Momo';
String BDNames = 'LDE_Name';
String BDValues = 'LDE_Value';
String url='http://213.139.98.70:8002/REST/CallManager/UpdateOpenCall/Agent?Switch=1'
+ '&Agent=' + EncodingUtil.urlEncode(agent,'UTF-8')
+ '&BDNames=' + EncodingUtil.urlEncode(BDNames,'UTF-8')
+ '&BDValues=' + EncodingUtil.urlEncode(BDValues,'UTF-8')
+ '&Overwrite=-1';
Test.startTest();
// Set mock callout class
Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
MockHttpResponseGenerator test1 = new MockHttpResponseGenerator();
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
system.assertEquals(req.getEndpoint(), url);
req.setMethod('GET');
Http h = new Http();
// Call method to test.
// This causes a fake response to be sent
// from the class that implements HttpCalloutMock.
TR004Object.GetIdObject(ObjIds);
TR004Object.callWSGetIdObject(Obj);
HttpResponse res = test1.respond(req);
System.assert(CurrentUser.CRC__c=='WebHelp');
//TR004Object.checkWsSuccessGetIdObject(res, Obj);
// Verify response received contains fake values
String contentType = res.getHeader('Content-Type');
System.assert(contentType == 'text/xml');
String actualValue = res.getbody();
String expectedValue ='<Output xmlns=\"nice.uniform://\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Data i:nil="true"/><Result xmlns:a=\"http://nice"><a:ResultCode>RESULTCODE</a:ResultCode><a:ResultMessage>No open call exists</a:ResultMessage><a:ResultCodeEx>CLS_SE_NO_OPEN_CALL</a:ResultCodeEx></Result><Exception i:nil="true" xmlns:a="http://schemas.datacontract.org/2004/07/System"/></Output>';
System.assertEquals(actualValue, expectedValue);
//System.assert(doc.load(expectedValue)!=null);
// System.assert(doc!=null);
String result = res.getbodyDocument().getRootElement().getChildElements()[1].getName();
String data= res.getbodyDocument().getRootElement().getChildElements()[0].getName();
String root = res.getbodyDocument().getRootElement().getName();
System.assertEquals(200, res.getStatusCode());
System.assertEquals('Result', result);
System.assertEquals('Data', data);
System.assertEquals('Output', root);
Test.stopTest();
}
}
Best Answer
You're really close with the code you have. The mistake is that you're testing against the mock class after the Test.setMock instead of testing against your non-test class's wrapper method and callout method. The Test.setMock method tells the test framework to swap out the response data from your non-test class's callout.
You'll also need to remove the logic check you have in place in your callout method so it can properly populate the HttpResponse object.
I can see you modeled this off of the documentation for the Test.setMock. The problem with their example is that their non-test method responds back with the HttpResponse object. That example is very basic since the method only returns the HttpResponse directly, but given the context of the feature, it is slightly tricky and confuses the issue.
https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_testing_httpcalloutmock.htm
An easier example to think of is a REST service taking in 1 integer, and returning two integers, and your non-test method that performs the callout also processes it like most test accessible(public/global) callout methods tend to do. Like all other tests your job is to make sure the method itself (and its wrapper @future) function as expected when given the right inputs, and that their output is valid. Test.setMock is only used so you can populate the response data in the non-test method with expected data (also because test can't run callout). Ideally you'd write a few versions of this test with varying values and callout responses including a test that returned invalid responses or exception catching states (e.g. blank response, XML with no nodes except parent, missing an XML node that is critical).
[[example coming later, it's super late here]]