i have written a test class for a controller in which one of the method makes a callout. This is one single invocation of external SAP webservice. But my debug log shows more than 10 invocation of the webservice but my code actually does not. I already wrote webservice mock implementation class. What could be the issue? If needed i can provide the entire source here.
Source Code:
Generated class from WSDL
//Generated by wsdl2apex
public class sapComDocumentSapSoapFunctionsMcS {
public class ZGssmwfmHndlEvntrqst00_element {
public String Dpi2Rtrvlastsaveddata;
public sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 DpistInpt;
private String[] Dpi2Rtrvlastsaveddata_type_info = new String[]{'Dpi2Rtrvlastsaveddata','urn:sap-com:document:sap:soap:functions:mc-style',null,'0','1','false'};
private String[] DpistInpt_type_info = new String[]{'DpistInpt','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style','false','true'};
private String[] field_order_type_info = new String[]{'Dpi2Rtrvlastsaveddata','DpistInpt'};
}
public class Z_GSSMWFM_HNDL_EVNTRQST00 {
//public String endpoint_x = 'http://xxxnj1:8050/sap/bc/srt/rfc/sap/z_gssmwfm_hndl_evntrqst00/110/z_gssmwfm_hndl_evntrqst00/z_gssmwfm_hndl_evntrqst00';
public String endpoint_x = 'http://xx.xx.xxx.10:8050/sap/bc/srt/rfc/sap/z_gssmwfm_hndl_evntrqst00/110/z_gssmwfm_hndl_evntrqst00/z_gssmwfm_hndl_evntrqst00';
public Map<String,String> inputHttpHeaders_x;
public Map<String,String> outputHttpHeaders_x;
public String clientCertName_x;
public String clientCert_x;
public String clientCertPasswd_x;
public Integer timeout_x;
private String[] ns_map_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style', 'sapComDocumentSapSoapFunctionsMcS', 'urn:sap-com:document:sap:rfc:functions', 'sapComDocumentSapRfcFunctions'};
public sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element ZGssmwfmHndlEvntrqst00(String Dpi2Rtrvlastsaveddata,sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 DpistInpt) {
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00_element request_x = new sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00_element();
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element response_x;
request_x.Dpi2Rtrvlastsaveddata = Dpi2Rtrvlastsaveddata;
request_x.DpistInpt = DpistInpt;
Map<String, sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element> response_map_x = new Map<String, sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element>();
response_map_x.put('response_x', response_x);
WebServiceCallout.invoke(
this,
request_x,
response_map_x,
new String[]{endpoint_x,
'',
'urn:sap-com:document:sap:soap:functions:mc-style',
'ZGssmwfmHndlEvntrqst00',
'urn:sap-com:document:sap:soap:functions:mc-style',
'ZGssmwfmHndlEvntrqst00Response',
'sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element'}
);
response_x = response_map_x.get('response_x');
return response_x;
}
}
public class Bapiret2 {
public String Type_x;
public String Id;
public String Number_x;
public String Message;
public String LogNo;
public String LogMsgNo;
public String MessageV1;
public String MessageV2;
public String MessageV3;
public String MessageV4;
public String Parameter;
public Integer Row;
public String Field;
public String System_x;
private String[] Type_x_type_info = new String[]{'Type','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] Id_type_info = new String[]{'Id','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] Number_x_type_info = new String[]{'Number','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] Message_type_info = new String[]{'Message','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] LogNo_type_info = new String[]{'LogNo','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] LogMsgNo_type_info = new String[]{'LogMsgNo','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] MessageV1_type_info = new String[]{'MessageV1','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] MessageV2_type_info = new String[]{'MessageV2','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] MessageV3_type_info = new String[]{'MessageV3','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] MessageV4_type_info = new String[]{'MessageV4','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] Parameter_type_info = new String[]{'Parameter','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] Row_type_info = new String[]{'Row','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] Field_type_info = new String[]{'Field','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] System_x_type_info = new String[]{'System','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style','false','true'};
private String[] field_order_type_info = new String[]{'Type_x','Id','Number_x','Message','LogNo','LogMsgNo','MessageV1','MessageV2','MessageV3','MessageV4','Parameter','Row','Field','System_x'};
}
public class ZgssmbssDatarcrd01 {
public String Cdata;
private String[] Cdata_type_info = new String[]{'Cdata','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style','false','true'};
private String[] field_order_type_info = new String[]{'Cdata'};
}
public class Bapiret2T {
public sapComDocumentSapSoapFunctionsMcS.Bapiret2[] item;
private String[] item_type_info = new String[]{'item','urn:sap-com:document:sap:soap:functions:mc-style',null,'0','-1','false'};
private String[] apex_schema_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style','false','true'};
private String[] field_order_type_info = new String[]{'item'};
}
public class ZgssmbstDatarcrd01 {
public sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01[] item;
private String[] item_type_info = new String[]{'item','urn:sap-com:document:sap:soap:functions:mc-style',null,'0','-1','false'};
private String[] apex_schema_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style','false','true'};
private String[] field_order_type_info = new String[]{'item'};
}
public class ZGssmwfmHndlEvntrqst00Response_element {
public sapComDocumentSapSoapFunctionsMcS.Bapiret2T DpostMssg;
public sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 DpostOtpt;
private String[] DpostMssg_type_info = new String[]{'DpostMssg','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] DpostOtpt_type_info = new String[]{'DpostOtpt','urn:sap-com:document:sap:soap:functions:mc-style',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:sap-com:document:sap:soap:functions:mc-style','false','true'};
private String[] field_order_type_info = new String[]{'DpostMssg','DpostOtpt'};
}
}
Controller extension:
public with sharing class OpenDocumentsController {
public Boolean displayOpenQuotations {get; set;}
public string pageSize {get;set;}
private final Account acct;
public String CustNo {get;set;}
public Integer offset { get; set;}
public Integer NumOf {get;set;}
public Double TotalAmount {get;set;}
public List<Quotation> lstQuotations {get;set;}
private List<String> lstReqData {get;set;}
private String EventType {get;set;}
private String InputFields {get;set;}
private String InputData {get;set;}
public OpenDocumentsController(ApexPages.StandardController stdController) {
displayOpenQuotations = true;
pageSize = '5';
if (!Test.isRunningTest()) {
List<String> addl = new List<String> {};
addl.add('accountnumber');
stdController.addFields(addl);
}
this.acct = (Account)stdController.getRecord();
System.debug('acct:'+acct);
if(CustNo == null) {
CustNo = acct.AccountNumber; //'1172';
}
//offset = 0;
System.debug('>>>>>>>>>>>>>>>>>offset'+offset);
}
//Method to get Open Quotations
public Quotation[] getOpenQuotations() {
lstReqData = new List<string> {};
try {
if(displayOpenQuotations == true && lstQuotations == null) {
offset = 0;
sapComDocumentSapSoapFunctionsMcS.Z_GSSMWFM_HNDL_EVNTRQST00 sap1 = new sapComDocumentSapSoapFunctionsMcS.Z_GSSMWFM_HNDL_EVNTRQST00();
Map<List<String>,List<List<String>>> mapSAP = new Map<List<String>,List<List<String>>> {};
sap1.timeout_x = 90000;
sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 req = new sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01();
List<List<String>> nlstData = new List<List<String>> {};
lstQuotations = new List<Quotation> {};
//DATA-TYPE[.]ZGSEVDST_OPENQTA[.]RESPONSE-TYPE=FULL-SETS;ROW-COUNT=1;[.]VBELN[.]AUDAT[.]KUNNR[.]NAME[.]NETWR[.]WAERK[.]ANGDT[.]BNDDT[.]QUNTITY
//ZGSEVDST_OPENQTA[.]20000039[.]2014-02-05[.]1172[.]CBD Computer Based Design[.]5145.00[.]USD[.]2014-02-05[.]2014-03-06[.]1 of ETO-A002 , 1 of 100-300 , 1 of GTS-14013
//populating item values
String EventType = 'EVENT[.]SFDC-OPEN-QUT-GET[.]VERSION[.]0[.]RESPONSE-TYPE[.]FULL-SETS';
String InputFields = 'SDCAS_T_CUSTLIST[.]'+CustNo;
String InputData = 'ZGSEVDST_SISINFOINPU[.]'+CustNo;
lstReqData.add(EventType);
lstReqData.add(InputFields);
lstReqData.add(InputData);
req.item = LoadRequestData(lstReqData);
sap1.timeout_x = 90000;
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element ret = sap1.ZGssmwfmHndlEvntrqst00('',req);
}
}Catch(Exception e) {
Apexpages.Message msg = new Apexpages.Message(Apexpages.Severity.FATAL,'Oops, please try again!!');
Apexpages.addMessage(msg);
}
return lstQuotations;
}
public void nextPage() {
}
public void previousPage() {
offset = Math.max(0, offset - 5);
}
public void lastPage() {
}
public void firstPage() {
offset = 0;
}
/*
Wrapper for Open Quotations
Doc Number Doc Date Customer Number Customer Name Amount CURRENCY VALID FROM DATE VALID TO DATE PRODUCTS
Quotation # Quotation Date
[.]AUDAT[.]KUNNR[.]NAME[.]NETWR[.]WAERK[.]ANGDT[.]BNDDT[.]QUNTITY
*/
public class Quotation{
public String DocNumber{get; set;} //VBELN
public String DocDate{get; set;} //AUDAT
public String CustomerNumber{get; set;} //KUNRG
public String CustomerName {get;set;} //NAME
public String Amount{get; set;} //NETWR
public String Curren{get; set;} //WAERK
public String ValidFromDt{get;set;} //ANGDT
public String ValidToDt{get;set;} //BNDDT
public String Product{get;set;} //QUNTITY
}
public static List<sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01> LoadRequestData(List<String> lstInput) {
List<sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01> itm = new List<sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01>();
//populating item values
sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01 s1 = new sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01();
s1.Cdata = 'DEVICE-ID:160000000000000:DEVICE-TYPE:SFDC-CLIENT:APPLICATION-ID:SFDC-SALES';
itm.add(s1);
sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01 s2 = new sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01();
s2.Cdata = 'NOTATION:ZML:VERSION:0:DELIMITER:[.]';
itm.add(s2);
for(String s: lstInput) {
sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01 s3 = new sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01();
s3.Cdata = s;
itm.add(s3);
}
System.debug('item values:'+itm);
return itm;
}
//Method to parse the response from the webservice call
public static Map<List<String>,List<List<String>>> ParseMultipleResponse(sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element ret) {
System.debug('Inside ParseMultipleResponse');
List<String> lstHeader = new List<String> {};
List<String> lstData = new List<String> {};
List<List<String>> nlstData = new List<List<String>> {};
Map<List<String>,List<List<String>>> mapSAP = new Map<List<String>,List<List<String>>> {};
System.debug('response value 1:'+ret.DpostMssg.item);
System.debug('response value 2:'+ret.DpostOtpt.item);
//if(ret.DpostMssg.item.isEmpty()) {
Integer cnt = 0;
for(sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01 r: ret.DpostOtpt.item) {
System.debug('cdata value:'+r.Cdata);
if(cnt == 2) {
lstHeader = r.Cdata.split('\\[.]');
}
if(cnt >= 3) {
lstData = r.Cdata.split('\\[.]');
nlstData.add(lstData);
}
cnt ++;
}
System.debug('lstHeader:'+lstHeader);
System.debug('lstData:'+lstData);
System.debug('nlstData:'+nlstData);
mapSAP.put(lstHeader,nlstData);
//}
//System.debug('mapSAP:'+mapSAP);
return mapSAP;
}
public static String FormatDate(String s) {
if(s != null || s!= '') {
String[] dt = s.split('-');
return dt[1]+'-'+dt[2]+'-'+dt[0];
} else {
return '';
}
}
public static Boolean isCurrentMonthYear(String s) {
if(s!= null && s!= '') {
String[] dt = s.split('-');
if(Date.today().month() == Integer.valueOf(dt[1]) && String.valueOf(Date.today().year()) == dt[0]) {
return true;
}
}
return false;
}
}
WebserviceMockImpl class:
@isTest
global class WebServiceMockImpl implements WebServiceMock {
global void doInvoke(
Object stub,
Object request,
Map<String, Object> response,
String endpoint,
String soapAction,
String requestName,
String responseNS,
String responseName,
String responseType) {
sapComDocumentSapSoapFunctionsMcS.Z_GSSMWFM_HNDL_EVNTRQST00 sap1 = new sapComDocumentSapSoapFunctionsMcS.Z_GSSMWFM_HNDL_EVNTRQST00();
sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 req = new sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01();
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element ret = sap1.ZGssmwfmHndlEvntrqst00('',req);
sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01 zg = new sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01();
//zg.Cdata = 'test';
sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 str = new sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01();
zg.Cdata = 'DATA-TYPE[.]ZGSEVDST_MATPRICE[.]RESPONSE-TYPE=FULL-SETS;ROW-COUNT=1;[.]KUNNR[.]MATNR[.]KBETR[.]KONWA';
str.item.add(zg);
zg.Cdata = 'ZGSEVDST_MATPRICE[.][.]100-100[.]85.00[.]USD';
str.item.add(zg);
//sapComDocumentSapSoapFunctionsMcS.ZgssmbssDatarcrd01[] item;
//item.add(zg);
//req.item = zg;
ret.DpostOtpt = str;
System.debug('return from test:'+ret);
response.put('response_x', ret.DpostOtpt);
}
}
Test class for the controller:
@isTest
public with sharing class testOpenDocumentsController {
public static testMethod void testOpenDocuments() {
Account a = new Account(Name='Tester', AccountNumber='1172');
insert a;
Test.startTest();
ApexPages.StandardController sc = new ApexPages.standardController(a);
OpenDocumentsController OD = new OpenDocumentsController(sc);
Test.setMock(WebServiceMock.class, new WebServiceMockImpl());
OD.getOpenQuotations();
Test.stopTest();
//System.assertEquals(e.acct, a);
}
}
Issue:
System.LimitException: Too many callouts: 11
Attribution to: Bforce
Possible Suggestion/Solution #1
I must admit I don't fully know how your mock implementation should look like, but I do think I understand what's going wrong in your version.
A mockservice should "simply" (may not be simple at all) return a response as your service callout is intended to respond. The mockservice class, is not intended to make any call outs (or attempts) - as this would trigger a recursive cycle in a test context where the mockservice is set.
Your mock service contains the line:
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element ret = sap1.ZGssmwfmHndlEvntrqst00('',req);
This is attempting to perform the webcall out ..
public sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element ZGssmwfmHndlEvntrqst00(String Dpi2Rtrvlastsaveddata, sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 DpistInpt) {
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00_element request_x = new sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00_element();
sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element response_x;
request_x.Dpi2Rtrvlastsaveddata = Dpi2Rtrvlastsaveddata;
request_x.DpistInpt = DpistInpt;
Map < String, sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element > response_map_x = new Map < String, sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element > ();
response_map_x.put('response_x', response_x);
WebServiceCallout.invoke(
this,
request_x,
response_map_x,
new String[] {
endpoint_x,
'',
'urn:sap-com:document:sap:soap:functions:mc-style',
'ZGssmwfmHndlEvntrqst00',
'urn:sap-com:document:sap:soap:functions:mc-style',
'ZGssmwfmHndlEvntrqst00Response',
'sapComDocumentSapSoapFunctionsMcS.ZGssmwfmHndlEvntrqst00Response_element'
}
);
response_x = response_map_x.get('response_x');
return response_x;
}
which in a test context where this mockservice is set will lauch a new mock instance, which will launch a new webcall out , which will launch a new mock instance, which will launch a new ... etc untill you hit the 11 call outs governor limit.
Update:
As the webcall method returns you an ZGssmwfmHndlEvntrqst00Response_element
object, your WebServiceMockImpl.doInvoke()
method should be COMPOSING such a record and add it to the response map.
public class ZGssmwfmHndlEvntrqst00Response_element {
public sapComDocumentSapSoapFunctionsMcS.Bapiret2T DpostMssg;
public sapComDocumentSapSoapFunctionsMcS.ZgssmbstDatarcrd01 DpostOtpt;
private String[] DpostMssg_type_info = new String[] {'DpostMssg', 'urn:sap-com:document:sap:soap:functions:mc-style', null, '1', '1', 'false'};
private String[] DpostOtpt_type_info = new String[] {'DpostOtpt', 'urn:sap-com:document:sap:soap:functions:mc-style', null, '1', '1', 'false'};
private String[] apex_schema_type_info = new String[] {'urn:sap-com:document:sap:soap:functions:mc-style', 'false', 'true'};
private String[] field_order_type_info = new String[] {'DpostMssg', 'DpostOtpt'};
}
As only the DpostMssg
and DpostOtpt
fields aren't populated, I guess that you should try to put some content in there. I would try to get some real responses from the webservice, either by debugging through apex (not in test mode) or using a tool like SOAPUI. This so that you know what response data from this webservice actually looks like, and so that you can copy a response with content required for your tests in your mockservice.
Attribution to: Samuel De Rycke
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/32374