+ Start a Discussion
MTBRiderMTBRider 

Re-Posting - Collection Store Exception

Sorry for re-posting this but I am stuck on this and will not be able to deploy unless I get t fixed...

I am getting a Collection Store Exception using WebServiceMock in my test.  Here is my original post...
 
https://developer.salesforce.com/forums/ForumsMain?id=906F0000000AhHlIAK

Since the last post on the above discussion, I have tried upgrading all classes involved including the test classes to API ver 31.0, changing the response_x map label on one of the web services methods in the wsdl generated class to response_y so that the two web service method responses do not reference the same response map label.  

No matter what I change, I always get the same exception using WebServiceMock.  I must be missing something.   Anyone? 
Best Answer chosen by MTBRider
kaustav goswamikaustav goswami
Did some further enhancements. I was thinking about brining in the two test in the same call. I have taken the help of a static variable to achieve this. Here is  what I ahve done.

Step 1:

The class that calls the method of the stub to invoke the webserice. - No change - same as posted above by me.

public class CallMockImplService{
    
    // do the callout
    public static String doCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String respString = stubInst.init('test_endpoint', 'test_u', 'test_p',true);
        return respString;
    }
    
    public static String[] doSecondCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String[] reqStrArr = new String[]{'value1', 'value2'};
        String[] responseArr = stubInst.processSFChanges('list_changes',reqStrArr);
        System.debug('#### mock response received #### ' + responseArr);
        return responseArr;
    }   
}

Step 2:

Implement the Mock interface like this in a class. Change is that the previous two classes has been merged into one class.

@isTest
global class WebSrcMockCallOut implements WebServiceMock{
    public static String indicatorVar;
    global void doInvoke(Object stub,
        Object request,
        Map<String, Object> response,
        String endpoint,
        String soapAction,
        String requestName,
        String responseNS,
        String responseName,
        String responseType
        ){
            if(indicatorVar == 'init'){
                SFLMBridgeWS.initResponse_element respElem = new SFLMBridgeWS.initResponse_element();
                respElem.initReturn = 'Mock_Response';
                response.put('response_x', respElem);
            }else if(indicatorVar == 'sync'){
                SFLMBridgeWS.processSFChangesResponse_element respElem = new SFLMBridgeWS.processSFChangesResponse_element();
                String[] arrStr = new String[]{'reponse1','response2'};
                respElem.processSFChangesReturn = arrStr;
                response.put('response_x', respElem);
            }
            
        }
}

Step 3:

A test class that calls these two methods and receives the responses accordingly. Change is that now instead of two separate methods only one test method will do the job.

@isTest
public class ExecuteMockCalloutTest{
    
    public static testMethod void doCombinedTest(){
        // set the mock response
        Test.setMock(WebServiceMock.class, new WebSrcMockCallOut());
        
        // set the sttaic value to get the response of the first callout
        WebSrcMockCallOut.indicatorVar = 'init';
        String result = CallMockImplService.doCallout();
        System.debug('#### response received #### ' + result);
        
        // set the static value to get the response of the second callout
        WebSrcMockCallOut.indicatorVar = 'sync';
        String[] respRec = CallMockImplService.doSecondCallout();
        System.debug('#### response from second callout #### ' + respRec);
    }
}

Now both the callouts take place in a single transaction. And give back the responses conditionally. Sorry for posting such huge pieces of code. The scenario was interesting.

Please let me know if this helps.

Thanks,
Kaustav

All Answers

kaustav goswamikaustav goswami
Can you please post the stub that was generated by parsing the wsdl?

That will help us to get a look at the request and response element. In the mock interface implementation i think you will have to replicate that.

Thanks,
Kaustav
MTBRiderMTBRider
Sure, here it is....

As I said in my original post, I simplied many of the names.  In the below code, the original names are still there.  Thanks for our help.
public class SFLMBridgeWS {
	
	/*The following block was added or edited after generation from wsdl*/
	public class SFLMBridgeException extends Exception {}			//This will be used to throw custom exceptions for this service
	/* End of added block */
	
    public class processSFChanges_element {
        public String listName;
        public String[] sfChanges;
        private String[] listName_type_info = new String[]{'listName','http://www.sfconnect.com',null,'1','1','false'};
        private String[] sfChanges_type_info = new String[]{'sfChanges','http://www.sfconnect.com',null,'1','-1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'listName','sfChanges'};
    }
    
    
    public class init_element {
        public String lmEndPoint;
        public String u;
        public String p;
        public Boolean isMock;
        private String[] lmEndPoint_type_info = new String[]{'lmEndPoint','http://www.sfconnect.com',null,'1','1','false'};
        private String[] u_type_info = new String[]{'u','http://www.sfconnect.com',null,'1','1','false'};
        private String[] p_type_info = new String[]{'p','http://www.sfconnect.com',null,'1','1','false'};
        private String[] isMock_type_info = new String[]{'isMock','http://www.sfconnect.com',null,'1','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'lmEndPoint','u','p','isMock'};
    }
    
    
    public class processSFChangesResponse_element {
        public String[] processSFChangesReturn;
        private String[] processSFChangesReturn_type_info = new String[]{'processSFChangesReturn','http://www.sfconnect.com',null,'1','-1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'processSFChangesReturn'};
    }
    
    
    public class initResponse_element {
        public String initReturn;
        private String[] initReturn_type_info = new String[]{'initReturn','http://www.sfconnect.com',null,'1','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'initReturn'};
    }
    
    
    public class ListSyncWS {
        /*The following block was added or edited after generation from wsdl*/
        public String endpoint_x;
        /* End of added block */
        
        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[]{'http://www.sfconnect.com', 'SFLMBridgeWS'};
        
        
        public String init(String lmEndPoint,String u,String p,Boolean isMock) {
            SFLMBridgeWS.init_element request_x = new SFLMBridgeWS.init_element();
            request_x.lmEndPoint = lmEndPoint;
            request_x.u = u;
            request_x.p = p;
            request_x.isMock = isMock;
            SFLMBridgeWS.initResponse_element response_x;
            Map<String, SFLMBridgeWS.initResponse_element> response_map_x = new Map<String, SFLMBridgeWS.initResponse_element>();
            response_map_x.put('response_x', response_x);
            
            /* The following block was added or edited after generation from wsdl */
            //End point is saved in the custom settings so that this code can be easily migrated from sandbox to production
            List<LMBridgeSettings__c> brdgSettings = LMBridgeSettings__c.getall().values();
            if (brdgSettings.isEmpty()) {
            	throw new SFLMBridgeException('No LMBridgeSettings__c Custom Setting found.');
            } else {
            	if ( String.isNotBlank(brdgSettings[0].SFLMBridgeEndPoint__c) )
            		endpoint_x = brdgSettings[0].SFLMBridgeEndPoint__c;
        		else {
        			throw new SFLMBridgeException('No value found for the SFLMBridgeEndPoint__c field of the LMBridgeSettings__c Custom Setting.');	
        		}
            }
            /* End of added block */
            
            
            WebServiceCallout.invoke(
              this,
              request_x,
              response_map_x,
              new String[]{endpoint_x,
              '',
              'http://www.sfconnect.com',
              'init',
              'http://www.sfconnect.com',
              'initResponse',
              'SFLMBridgeWS.initResponse_element'}
            );
            response_x = response_map_x.get('response_x');
           return response_x.initReturn;
        }
       	       	
       
        public String[] processSFChanges(String listName,String[] sfChanges) {
            SFLMBridgeWS.processSFChanges_element request_x = new SFLMBridgeWS.processSFChanges_element();
            request_x.listName = listName;
            request_x.sfChanges = sfChanges;
            SFLMBridgeWS.processSFChangesResponse_element response_x;
            Map<String, SFLMBridgeWS.processSFChangesResponse_element> response_map_x = new Map<String, SFLMBridgeWS.processSFChangesResponse_element>();
            response_map_x.put('response_x', response_x);
            
            /* The following block was added or edited after generation from wsdl */
            //End point is saved in the custom settings so that this code can be easily migrated from sandbox to production
            List<LMBridgeSettings__c> brdgSettings = LMBridgeSettings__c.getall().values();
            if (brdgSettings.isEmpty()) {
            	throw new SFLMBridgeException('No LMBridgeSettings__c Custom Setting found.');
            } else {
            	if ( String.isNotBlank(brdgSettings[0].SFLMBridgeEndPoint__c) )
            		endpoint_x = brdgSettings[0].SFLMBridgeEndPoint__c;
        		else {
        			throw new SFLMBridgeException('No value found for the SFLMBridgeEndPoint__c field of the LMBridgeSettings__c Custom Setting.');	
        		}
            }
            /* End of added block */
            
            WebServiceCallout.invoke(
              this,
              request_x,
              response_map_x,
              new String[]{endpoint_x,
              '',
              'http://www.sfconnect.com',
              'processSFChanges',
              'http://www.sfconnect.com',
              'processSFChangesResponse',
              'SFLMBridgeWS.processSFChangesResponse_element'}
            );
            response_x = response_map_x.get('response_x');
            return response_x.processSFChangesReturn;
        }
    } 
}
James LoghryJames Loghry
So I commented on your previous issue, but here your exception makes more sense..

Your processSFChanges method has a response_x variable of type "SFLMBridgeWS.initResponse_element"

Your Mock Callout class puts two instances of different classes into the "response_x" key of your response map.  One instance is of type "initResponse_element" and one is of type "syncResponse".   It's likely throwing an exception around line 137 above, becuase it can't cast from a syncResponse to an initResponse.

You'll likely need to break out your sync and init responses into separate mock callouts, or provide a mechanism, where you can pass in an array of responses, and then have your mock callout send the right one back based on either the number of callouts made in your unit test or based on a parameter in the request or something.

As an example, I had to implement a mock callout for a method that sent two callouts so here's how I handled it:

@isTest
global class test__mockcallout implements HttpCalloutMock{

    private List<String> responses {get; private set;}
    private boolean isExceptionThrown {get; private set;}

    //For handling multiple callout cases 
    public static Integer TEST_CALLOUT_INDEX = 0;

	global test_mockcallout(List<String> responses, boolean isExceptionThrown){
		this.responses = responses;
		this.isExceptionThrown = isExceptionThrown;
	}

	global HttpResponse respond(HttpRequest req){
		if(isExceptionThrown){
			throw new custom_Exception('Exception thrown');
		}

		HttpResponse resp = new HttpResponse();
		resp.setStatusCode(200);
		resp.setStatus('TEST');
		resp.setBody(this.responses.get(TEST_CALLOUT_INDEX));

		//Increment Callout Index for multiple callout processing in a single unit test.
		TEST_CALLOUT_INDEX++;
		return resp;
	}
}


kaustav goswamikaustav goswami
I did a test in my own dev org.

First I created a stub from the above code -

Had to comment out the custom settings part.

public class SFLMBridgeWS {
    
    /*The following block was added or edited after generation from wsdl*/
    //public class SFLMBridgeException extends Exception {}         //This will be used to throw custom exceptions for this service
    /* End of added block */
    
    public class processSFChanges_element {
        public String listName;
        public String[] sfChanges;
        private String[] listName_type_info = new String[]{'listName','http://www.sfconnect.com',null,'1','1','false'};
        private String[] sfChanges_type_info = new String[]{'sfChanges','http://www.sfconnect.com',null,'1','-1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'listName','sfChanges'};
    }
    
    
    public class init_element {
        public String lmEndPoint;
        public String u;
        public String p;
        public Boolean isMock;
        private String[] lmEndPoint_type_info = new String[]{'lmEndPoint','http://www.sfconnect.com',null,'1','1','false'};
        private String[] u_type_info = new String[]{'u','http://www.sfconnect.com',null,'1','1','false'};
        private String[] p_type_info = new String[]{'p','http://www.sfconnect.com',null,'1','1','false'};
        private String[] isMock_type_info = new String[]{'isMock','http://www.sfconnect.com',null,'1','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'lmEndPoint','u','p','isMock'};
    }
    
    
    public class processSFChangesResponse_element {
        public String[] processSFChangesReturn;
        private String[] processSFChangesReturn_type_info = new String[]{'processSFChangesReturn','http://www.sfconnect.com',null,'1','-1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'processSFChangesReturn'};
    }
    
    
    public class initResponse_element {
        public String initReturn;
        private String[] initReturn_type_info = new String[]{'initReturn','http://www.sfconnect.com',null,'1','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.sfconnect.com','true','false'};
        private String[] field_order_type_info = new String[]{'initReturn'};
    }
    
    
    public class ListSyncWS {
        /*The following block was added or edited after generation from wsdl*/
        public String endpoint_x;
        /* End of added block */
        
        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[]{'http://www.sfconnect.com', 'SFLMBridgeWS'};
        
        
        public String init(String lmEndPoint,String u,String p,Boolean isMock) {
            SFLMBridgeWS.init_element request_x = new SFLMBridgeWS.init_element();
            request_x.lmEndPoint = lmEndPoint;
            request_x.u = u;
            request_x.p = p;
            request_x.isMock = isMock;
            SFLMBridgeWS.initResponse_element response_x;
            Map<String, SFLMBridgeWS.initResponse_element> response_map_x = new Map<String, SFLMBridgeWS.initResponse_element>();
            response_map_x.put('response_x', response_x);
            
            /* The following block was added or edited after generation from wsdl */
            //End point is saved in the custom settings so that this code can be easily migrated from sandbox to production
            /*List<LMBridgeSettings__c> brdgSettings = LMBridgeSettings__c.getall().values();
            if (brdgSettings.isEmpty()) {
                throw new SFLMBridgeException('No LMBridgeSettings__c Custom Setting found.');
            } else {
                if ( String.isNotBlank(brdgSettings[0].SFLMBridgeEndPoint__c) )
                    endpoint_x = brdgSettings[0].SFLMBridgeEndPoint__c;
                else {
                    throw new SFLMBridgeException('No value found for the SFLMBridgeEndPoint__c field of the LMBridgeSettings__c Custom Setting.'); 
                }
            }
            /* End of added block */
            
            
            WebServiceCallout.invoke(
              this,
              request_x,
              response_map_x,
              new String[]{endpoint_x,
              '',
              'http://www.sfconnect.com',
              'init',
              'http://www.sfconnect.com',
              'initResponse',
              'SFLMBridgeWS.initResponse_element'}
            );
            response_x = response_map_x.get('response_x');
           return response_x.initReturn;
        }
                
       
        public String[] processSFChanges(String listName,String[] sfChanges) {
            SFLMBridgeWS.processSFChanges_element request_x = new SFLMBridgeWS.processSFChanges_element();
            request_x.listName = listName;
            request_x.sfChanges = sfChanges;
            SFLMBridgeWS.processSFChangesResponse_element response_x;
            Map<String, SFLMBridgeWS.processSFChangesResponse_element> response_map_x = new Map<String, SFLMBridgeWS.processSFChangesResponse_element>();
            response_map_x.put('response_x', response_x);
            
            /* The following block was added or edited after generation from wsdl */
            //End point is saved in the custom settings so that this code can be easily migrated from sandbox to production
            /*List<LMBridgeSettings__c> brdgSettings = LMBridgeSettings__c.getall().values();
            if (brdgSettings.isEmpty()) {
                throw new SFLMBridgeException('No LMBridgeSettings__c Custom Setting found.');
            } else {
                if ( String.isNotBlank(brdgSettings[0].SFLMBridgeEndPoint__c) )
                    endpoint_x = brdgSettings[0].SFLMBridgeEndPoint__c;
                else {
                    throw new SFLMBridgeException('No value found for the SFLMBridgeEndPoint__c field of the LMBridgeSettings__c Custom Setting.'); 
                }
            }
            /* End of added block */
            
            WebServiceCallout.invoke(
              this,
              request_x,
              response_map_x,
              new String[]{endpoint_x,
              '',
              'http://www.sfconnect.com',
              'processSFChanges',
              'http://www.sfconnect.com',
              'processSFChangesResponse',
              'SFLMBridgeWS.processSFChangesResponse_element'}
            );
            response_x = response_map_x.get('response_x');
            return response_x.processSFChangesReturn;
        }
    } 
}

Step 2: Created a class that does a callout

public class CallMockImplService{
    
    // do the callout
    public static String doCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String respString = stubInst.init('test_endpoint', 'test_u', 'test_p',true);
        return respString;
    }   
}

Step 3: I created a class that implements the mock web service interface

@isTest
global class WebSrcMockCallOut 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
        ){
            SFLMBridgeWS.initResponse_element respElem = new SFLMBridgeWS.initResponse_element();
            respElem.initReturn = 'Mock_Response';
            response.put('response_x', respElem);
        }
}

Step 4: Created a test class that executes the method

@isTest
public class ExecuteMockCalloutTest{
    public static testmethod void testMockImpl(){
        Test.setMock(WebServiceMock.class, new WebSrcMockCallOut());
        String result = CallMockImplService.doCallout();
        System.debug('#### response received #### ' + result);
    }
}

This executed fine. For your other method that has a web service call out invoke please implement the interface and create a similar fake response.

Please let us know if this works.

Thanks,
Kaustav
MTBRiderMTBRider
Thanks for your responses Kaustav and James!

Kaustav, I believe you are not getting this exception in your dev org because your class that is making the call out is only calling one of the ws methods.  If you call both the .init() and the .processSFChanges() you will get the same exception.  If you don't, then let me know!   In my environment, if I comment out the .Init() call in my callout method and only call .processSFChanges(), I do not get the exception either. 

James, I already tried to break up the mock responses into different classes:

@isTest
global class SFLMBridgeInitMock implements WebServiceMock {
    public String initResponse;
    
    global void doInvoke(Object stub, 
                        Object request, 
                        Map<String, Object> response,   
                        String endpoint, 
                        String soapAction,
                        String requestName, 
                        String responseNS, 
                        String responseName,    
                        String responseType)                {
        
        SFLMBridgeWS.initResponse_element resp = new SFLMBridgeWS.initResponse_element();
        resp.initReturn = 'initTest';
        response.put('response_x', (Object)resp);
    }
}


@isTest
global class SFLMBridgeDoSyncMock implements WebServiceMock {
	public List<String> processSFChangesResponse;
	
	global void doInvoke(Object stub, 
					Object request, 
					Map<String, Object> response,	
					String endpoint, 
					String soapAction,
					String requestName,	
					String responseNS, 
					String responseName,	
					String responseType) 		{
		SFLMBridgeWS.processSFChangesResponse_element resp = new SFLMBridgeWS.processSFChangesResponse_element();
		resp.processSFChangesReturn = new List<String>{'Sync:Test:success'};
		response.put('response_x', (Object)resp);
	}
}
Then in my test class: 

....

//Create a bunch of contacts to insert.  The Trigger will call the @future callout method

.....

SFLMBridgeInitMock wsMock1 = new SFLMBridgeInitMock();
Test.setMock(WebServiceMock.class, wsMock1);
        
SFLMBridgeDoSyncMock wsMock2 = new SFLMBridgeDoSyncMock();
Test.setMock(WebServiceMock.class, wsMock2);
        
Test.startTest();
   insert tstCons;
Test.stopTest();

....
I don't believe the problem is in the mock response classes I created.   I think the problem may be an issue with WebServiceMock class that they implement.

Even if I call only one of the mock response classes in my test I will get that same exception...  

If I call only the SFLMBridgeInitMock() class in my test I will get:

Collection store exception putting SFLMBridgeWS.initResponse_element into MAP<String,SFLMBridgeWS.processSFChangesResponse_element>

On line 125 of the above class generated from the wsdl.

If I call only the SFLMBridgeDoSyncMock() class in my test I will get:

Collection store exception putting SFLMBridgeWS.processSFChangesResponse_element into MAP<String,SFLMBridgeWS.initResponse_element>

on line 86 of the above class generated from the wsdl.

So I think the problem stems from the fact that my @future callout method is calling both of the ws methods.  This works fine when making the real callouts and responses, but for the mock callouts and responses, it looks like WebServiceMock is not able to handle the two different response types when trying to override the real callout responses.
kaustav goswamikaustav goswami
I enhanced the codes and executed the test class. It worked fine. I broke up the individual mock responses and then I set them and called them from two separate test methods.

Class that makes the call outs:

public class CallMockImplService{
    
    // do the callout
    public static String doCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String respString = stubInst.init('test_endpoint', 'test_u', 'test_p',true);
        return respString;
    }
    
    public static String[] doSecondCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String[] reqStrArr = new String[]{'value1', 'value2'};
        String[] responseArr = stubInst.processSFChanges('list_changes',reqStrArr);
        System.debug('#### mock response received #### ' + responseArr);
        return responseArr;
    }   
}

Mock Response for first callout:

@isTest
global class WebSrcMockCallOut 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
        ){
            SFLMBridgeWS.initResponse_element respElem = new SFLMBridgeWS.initResponse_element();
            respElem.initReturn = 'Mock_Response';
            response.put('response_x', respElem);
        }
}

Mock response for second callout:

@isTest
global class WebSrcMockCallOut2 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
        ){
            SFLMBridgeWS.processSFChangesResponse_element respElem = new SFLMBridgeWS.processSFChangesResponse_element();
            String[] arrStr = new String[]{'reponse1','response2'};
            respElem.processSFChangesReturn = arrStr;
            response.put('response_x', respElem);
        }
}

Test class to execute the two tests:

@isTest
public class ExecuteMockCalloutTest{
    public static testmethod void testMockImpl(){
        Test.setMock(WebServiceMock.class, new WebSrcMockCallOut());
        String result = CallMockImplService.doCallout();
        System.debug('#### response received #### ' + result);
    }
    
    public static testMethod void testSecondMethod(){
        Test.setMock(WebServiceMock.class, new WebSrcMockCallOut2());
        String[] respRec = CallMockImplService.doSecondCallout();
        System.debug('#### response from second callout #### ' + respRec);
    }
}

Ley me know if this helps. I have broken up the calls and their responses in separate test and theat seems to work.

Thanks,
Kaustav
kaustav goswamikaustav goswami
Did some further enhancements. I was thinking about brining in the two test in the same call. I have taken the help of a static variable to achieve this. Here is  what I ahve done.

Step 1:

The class that calls the method of the stub to invoke the webserice. - No change - same as posted above by me.

public class CallMockImplService{
    
    // do the callout
    public static String doCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String respString = stubInst.init('test_endpoint', 'test_u', 'test_p',true);
        return respString;
    }
    
    public static String[] doSecondCallout(){
        SFLMBridgeWS.ListSyncWS stubInst = new SFLMBridgeWS.ListSyncWS();
        stubInst.endpoint_x = 'http://test.mockcallout.com/service';
        String[] reqStrArr = new String[]{'value1', 'value2'};
        String[] responseArr = stubInst.processSFChanges('list_changes',reqStrArr);
        System.debug('#### mock response received #### ' + responseArr);
        return responseArr;
    }   
}

Step 2:

Implement the Mock interface like this in a class. Change is that the previous two classes has been merged into one class.

@isTest
global class WebSrcMockCallOut implements WebServiceMock{
    public static String indicatorVar;
    global void doInvoke(Object stub,
        Object request,
        Map<String, Object> response,
        String endpoint,
        String soapAction,
        String requestName,
        String responseNS,
        String responseName,
        String responseType
        ){
            if(indicatorVar == 'init'){
                SFLMBridgeWS.initResponse_element respElem = new SFLMBridgeWS.initResponse_element();
                respElem.initReturn = 'Mock_Response';
                response.put('response_x', respElem);
            }else if(indicatorVar == 'sync'){
                SFLMBridgeWS.processSFChangesResponse_element respElem = new SFLMBridgeWS.processSFChangesResponse_element();
                String[] arrStr = new String[]{'reponse1','response2'};
                respElem.processSFChangesReturn = arrStr;
                response.put('response_x', respElem);
            }
            
        }
}

Step 3:

A test class that calls these two methods and receives the responses accordingly. Change is that now instead of two separate methods only one test method will do the job.

@isTest
public class ExecuteMockCalloutTest{
    
    public static testMethod void doCombinedTest(){
        // set the mock response
        Test.setMock(WebServiceMock.class, new WebSrcMockCallOut());
        
        // set the sttaic value to get the response of the first callout
        WebSrcMockCallOut.indicatorVar = 'init';
        String result = CallMockImplService.doCallout();
        System.debug('#### response received #### ' + result);
        
        // set the static value to get the response of the second callout
        WebSrcMockCallOut.indicatorVar = 'sync';
        String[] respRec = CallMockImplService.doSecondCallout();
        System.debug('#### response from second callout #### ' + respRec);
    }
}

Now both the callouts take place in a single transaction. And give back the responses conditionally. Sorry for posting such huge pieces of code. The scenario was interesting.

Please let me know if this helps.

Thanks,
Kaustav
This was selected as the best answer
MTBRiderMTBRider
No need to apologize, I appreciate the help!

Based on your last response, which was something that James also suggested in his post, I went back and modified my mock response class so that it had a "switch" that would set one reponse or the other based on how many times the mock response's doInvoke method was called.  Here is the code:

@isTest
public class SFLMBridgeWSMock implements WebServiceMock {
	public static Integer typeOfResp = 0;
	public String initResp;
	public List<String> processResp;
		
	public void doInvoke(Object stub, 
							Object request, 
							Map<String, Object> response,	
							String endpoint, 
							String soapAction,
							String requestName,	
							String responseNS, 
							String responseName,	
							String responseType) 				{
			
		if (typeOfResp == 0) {
			SFLMBridgeWS.initResponse_element resp = new SFLMBridgeWS.initResponse_element();
			resp.initReturn = initResp;
			response.put('response_x', resp);
			typeOfResp = 1;
		} else if (typeOfResp == 1) {
			SFLMBridgeWS.processSFChangesResponse_element resp = new SFLMBridgeWS.processSFChangesResponse_element();
			resp.processSFChangesReturn = processResp;
			response.put('response_x', resp);
		} else {
			system.debug('.............typeOfResp = ' + String.valueOf(typeOfResp) + '.  Invalid typeOfResp value.');
		}
	}	
}

The way the web service is implemented, the init ws method is only called once to login to the ws, then processSFChanges can be called multiple times depending on what changes there are to process.  So, once I mock up the init response the first time, I am only needing the processResp until I re-instaniate the mock response class again.

The relevent parts of the test method now look like this:

        List<Contact> tstCons = new List<Contact>();
        List<String> procResp = new List<String>();
        
        ....   

                //create a list of contacts to insert and a list of mock responses
       
        ....


        SFLMBridgeWSMock wsMock = new SFLMBridgeWSMock();
        wsMock.initResp = 'success';
        wsMock.processResp = procResp;
        Test.setMock(WebServiceMock.class, wsMock);
        
        Test.startTest();
        insert tstCons;
        Test.stopTest();

Thanks for you help James and Kaustav!   

I wish I could give both of you the Best Answer designation, but I don't think I can....