I'd really appreciate any suggestions that the group may have.
I'm writing a test class for a SalesForce trigger that calls a webservice.
The trigger works fine in the Sandbox environment, but when I attempt to run a test class against it with a mock webservice, the mock webservice is getting called over and over and over, until I get a 'too many callouts' error.
I tried inserting code so that the mock webservice stops returning mock data after the third callout (using Limits.getCallouts), the test returns an error saying 'attempt to de-reference a null object'.
The general design is that a trigger calls a webservice defined in a separate class. This class generates a request and a response (the request and the response were mapped by importing WSDLs into SalesForce).
I'm almost certain that the trigger and webservice class are only called once (I used system.debug messages to determine this); the multiple callouts all seem to be at the mock Webservice in the test class.
Per a suggestion that was made in the form, I included my code: The first snippet of code is the test class. The second snippet of code is the trigger. The Third is the webservice call The Fourth is part I of the webservice The Fifth is part II of the webservice
@isTest
private class clsUpdateFromQadPrice_t {
static String strSprNbr;
private class WebServiceMockImpl implements WebServiceMock
{
public void doInvoke(
Object stub,
Object request,
Map<String, Object> response,
String endpoint,
String soapAction,
String requestName,
String responseNS,
String responseName,
String responseType)
{
system.debug(Limits.getCallouts());
system.debug('-------------------===============-------------');
system.debug(request);
if (request instanceof QADXxsfptexpXxsfptexp.xxsfptexp_element && Limits.getCallouts() < 3) {
system.debug('--This is the code that keeps getting looped over and over and over ---');
system.debug('-----------Type------------');
system.debug('QADXxsfptexpXxsfptexp.xxsfptexp_element');
QADXxsfptexp.xxsfptexpObj qadDataReq = new QADXxsfptexp.xxsfptexpObj();
QADXxsfptexpXxsfptexp.xxsfptexpResponse_element qadResponse = new QADXxsfptexpXxsfptexp.xxsfptexpResponse_element();
qadResponse = qadDataReq.xxsfptexp('blah');
qadResponse.pcOutput = 'blahblah';
qadResponse.result = 'Yes';
response.put('response_x', qadResponse);
}
system.debug('----===---===----');
system.debug ('Stub: ' + stub);
system.debug ('Request: ' + request);
system.debug ('Response: ' + response);
system.debug ('Endpoint: ' + endpoint);
system.debug ('SoapAction: ' + soapAction);
system.debug ('Request Name: ' + requestName);
system.debug ('Response NS: ' + responseNS);
system.debug ('Response Name: ' + responseName);
system.debug ('Request Type: ' + responseType);
}
}
@isTest static void test_clsUpdateFromQadPrice() {
test.startTest();
/* System.test.SetMock(WebServiceMock.class, new WebServiceMockImpl()); */
String CRON_EXP = '0 1 * * * ?';
clsUpdateFromQadPrice sch = new clsUpdateFromQadPrice();
system.schedule('SF Update from QAD - 45', CRON_EXP, sch);
test.stopTest();
}
@isTest static void test_clsUpdateFromQadPriceCallout() {
test.startTest();
System.test.SetMock(WebServiceMock.class, new WebServiceMockImpl());
/* Create new Price Approval__c record for testing */
Price_Approval__c prc = new Price_Approval__c();
prc.Government_Bid__c = 'Yes';
prc.Start_Date__c = Date.newInstance(2016, 12, 9);
prc.Expiration_Date__c = Date.newInstance(2020, 12, 9);
prc.Account_Name__c = '001G000000s7L7jIAE';
prc.US_Entered_into_QAD__c = 'Pending';
prc.US_Project_Pricing__c = 'No';
system.debug('=======');
try {
system.debug('-->Trying ..');
insert prc;
/* Use select statement to retrieve the newly-created name */
prc = [select id, Name from Price_Approval__c where id = :prc.id LIMIT 1];
system.debug('Name--->: ' + prc.Name);
strSprNbr = prc.Name;
prc.Approval_Status__c = 'Approved';
update prc;
}
catch (Exception e) {
system.debug('Caught..');
system.debug('-->Heres the problem: ' + e.getMessage());
}
/* Create detail record */
Price_Approval_Details__c prd = new Price_Approval_Details__c();
prd.US_Prod_Description__c = 'Description';
prd.Part_No__C = 'ItemNumber';
prd.Qty__c = 100;
prd.Sell_Price__c = 125.55;
prd.Price_Approval_Detail__c = prc.Id;
try {
insert prd;
prd = [select id, Name from Price_Approval_Details__c where id = :prd.id LIMIT 1];
system.debug('created PRD');
update prd;
}
catch (exception e) {
system.debug('PRD Issue: ' + e.getMessage());
}
test.stopTest();
}
}
This is the trigger
trigger trg_updateSprDetail on Price_Approval_Details__c (Before Update) {
set<id> samp = new set<id>();
system.debug('-----------------');
for (Price_Approval_Details__c pd:trigger.new) {
string strRequest;
/* Get Account Number */
for (Price_Approval__c ppa :[Select Id, Name, Account_Name__c, Account_No__c FROM Price_Approval__c WHERE Price_Approval__c.Id = :pd.Price_Approval_Detail__c]) {
system.debug(ppa.Name);
strRequest = 'BRK' + '|' +
ppa.Account_No__c + '|' +
pd.Part_No__c;
}
if (!System.isFuture() && !Test.isRunningTest()) {
clsGetQadItemData.updateSfSPRDetail(pd.Id, strRequest);
}
}
}
This is the web service class
global class clsGetQadItemData {
@future(callout=true)
webservice static void updateSfSPRDetail(ID sprDetailId, String strInput) {
system.debug('I am running this ...' + strInput);
system.debug('Thelimitis: ' + Limits.getCallouts());
system.debug(strInput);
boolean blUpdateSprDetail = false;
try {
system.debug('start');
QADXxsfptexp.xxsfptexpObj qadDataReq = new QADXxsfptexp.xxsfptexpObj();
QADXxsfptexpXxsfptexp.xxsfptexpResponse_element qadResponse = new QADXxsfptexpXxsfptexp.xxsfptexpResponse_element();
qadResponse = qadDataReq.xxsfptexp(strInput);
system.debug('stop');
List<String> strQadResult = qadResponse.pcOutput.split('\\|');
for (Integer i = 0; i<strQadResult.size(); i++) {
system.debug('Value at: ' + i + ' is: ' + strQadResult[i]);
}
for (Price_Approval_Details__c pad:[Select Id, Name, US_Proposed_Cost__c FROM Price_Approval_Details__c WHERE Id = :sprDetailId ]) {
try {
pad.Part_Status__c = strQadResult[02];
pad.List_Price__c = Decimal.ValueOf(strQadResult[03]);
pad.Old_Price__c = Decimal.ValueOf(strQadResult[04]);
pad.Customer_Part_No__c = strQadResult[06];
pad.US_PROD_Description__c = strQadResult[07];
pad.US_YTD_Avg_Price__c = Decimal.ValueOf(strQadResult[08]);
pad.US_YTD_Cost__c = Decimal.ValueOf(strQadResult[09]);
pad.US_YTD_Margin__c = Decimal.ValueOf(strQadResult[10]);
pad.US_YTD_Avg_Price__c = Decimal.ValueOf(strQadResult[11]);
pad.US_PriorYr_Avg_Price__c = Decimal.ValueOf(strQadResult[12]);
pad.US_PriorYr_Cost__c = Decimal.ValueOf(strQadResult[13]);
pad.US_PriorYr_Margin__c = Decimal.ValueOf(strQadResult[14]);
pad.US_PriorYr_Qty__c = Decimal.ValueOf(strQadResult[15]);
pad.US_3rdYr_Avg_Price__c = Decimal.ValueOf(strQadResult[16]);
pad.US_3rdYr_Cost__c = Decimal.ValueOf(strQadResult[17]);
pad.US_3rdYr_Margin__c = Decimal.ValueOf(strQadResult[18]);
pad.US_3rdYr_QTY__c = Decimal.ValueOf(strQadResult[19]);
update pad;
system.debug('Current and Prior Costs / Margins');
}
catch (exception e) {
system.debug ('ERROR during update of Costs / Margins: ' + e.getMessage());
}
try {
pad.US_TCC__c = Decimal.ValueOf(strQadResult[20]);
pad.Cost__c = Decimal.ValueOf(strQadResult[21]);
/* For German SPR Details ...
pad.US_Part__c = True;
*/
pad.Cost__c = Decimal.ValueOf(strQadResult[22]);
pad.VM__c = strQadResult[23];
update pad;
system.debug('Test 02');
}
catch (exception e) {
system.debug ('ERROR during update 2: ' + e.getMessage());
}
try {
system.debug('Updating TSC_c');
pad.TSC__c = Decimal.ValueOf(strQadResult[22]);
update pad;
}
catch (exception e) {
system.debug('Unable to update TSC_c' + e.getMessage());
}
try {
pad.US_Contract_Price__c = Decimal.ValueOf(strQadResult[24]);
pad.US_PL__c = strQadResult[25];
switch on (strQadResult[2]) {
when 'A' {
pad.Active_Part__c = 'Yes';
}
when 'a' {
pad.Active_Part__c = 'Yes';
}
when else {
pad.Active_Part__c = 'No';
}
}
system.debug('Test 03');
update pad;
}
catch (exception e) {
system.debug ('ERROR during update 1: ' + e.getMessage());
}
}
}
catch (exception e) {
}
}
}
this is the first part of the Webservice call
//Generated by wsdl2apex
public class QADXxsfptexp {
public class xxsfptexpObj {
/* Test */
public String endpoint_x = 'http://12.71.154.62:8080/wsa/wsa1';
/* Prod
public String endpoint_x = 'http://12.71.154.56:8080/wsa/wsa1';
*/
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:services-progress-com:xxsfptexp', 'QADXxsfptexp', 'urn:soap-fault:details', 'QADXxsfptexpsoapFaultDetails', 'urn:services-progress-com:xxsfptexp:xxsfptexp', 'QADXxsfptexpXxsfptexp'};
public QADXxsfptexpXxsfptexp.xxsfptexpResponse_element xxsfptexp(String pcInput) {
QADXxsfptexpXxsfptexp.xxsfptexp_element request_x = new QADXxsfptexpXxsfptexp.xxsfptexp_element();
request_x.pcInput = pcInput;
QADXxsfptexpXxsfptexp.xxsfptexpResponse_element response_x;
Map<String, QADXxsfptexpXxsfptexp.xxsfptexpResponse_element> response_map_x = new Map<String, QADXxsfptexpXxsfptexp.xxsfptexpResponse_element>();
response_map_x.put('response_x', response_x);
WebServiceCallout.invoke(
this,
request_x,
response_map_x,
new String[]{endpoint_x,
'',
'urn:services-progress-com:xxsfptexp:xxsfptexp',
'xxsfptexp',
'urn:services-progress-com:xxsfptexp:xxsfptexp',
'xxsfptexpResponse',
'QADXxsfptexpXxsfptexp.xxsfptexpResponse_element'}
);
response_x = response_map_x.get('response_x');
return response_x;
}
}
}
This is the second part of the Webservice call
//Generated by wsdl2apex
public class QADXxsfptexpXxsfptexp {
public class xxsfptexpResponse_element {
public String result;
public String pcOutput;
private String[] result_type_info = new String[]{'result','urn:services-progress-com:xxsfptexp:xxsfptexp',null,'1','1','true'};
private String[] pcOutput_type_info = new String[]{'pcOutput','urn:services-progress-com:xxsfptexp:xxsfptexp',null,'1','1','true'};
private String[] apex_schema_type_info = new String[]{'urn:services-progress-com:xxsfptexp:xxsfptexp','true','false'};
private String[] field_order_type_info = new String[]{'result','pcOutput'};
}
public class xxsfptexp_element {
public String pcInput;
private String[] pcInput_type_info = new String[]{'pcInput','urn:services-progress-com:xxsfptexp:xxsfptexp',null,'1','1','true'};
private String[] apex_schema_type_info = new String[]{'urn:services-progress-com:xxsfptexp:xxsfptexp','true','false'};
private String[] field_order_type_info = new String[]{'pcInput'};
}
}