1

Background

We are integrating with AWS Services, so we installed the Amazon Toolkit and right after installed we run the Apex Test Execution and we find out that there are 6 test methods not passing from 2 classes (S3 and EC2ConsoleController).

We decided to create our own test method, since the toolkit is from API Version 14.0, the test methods where inside the clase itself. In order to start editing we have to create a separate class for testing and all we did was to copy - paste the test methods from within S3 and EC2ConsoleController to two separate classes. Then we find out that we need to use Test.setMock() in order to run the failing methods or they were just skipped.

Aproach

So we started googling, and find out a lot of resources and topics about test.setMock() in general (Testing Web Service Callouts, Winter '13 Release Notes, stackexchange Question, Testing Apex Callouts using HttpCalloutMock, to mention a few...) and we tried to follow up and apply to our case but so far we have no luck.

Problem

We have created the class WebServiceMockImpl that implements WebServiceMock but we don't know what to put in the response element for it to work.

And in the S3_Test class methods 1 - 5 we don't know how to call the Test.setMock() method.

Mock

@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) {
            // Create response element from the autogenerated class.
            // Populate response element.
            // Add response element to the response parameter, as follows:
            //response.put('response_x', responseElement); 
        }
}

Test

@isTest
private class S3_Test{


    static testmethod void test1() {
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

        s3.ListBucketResponse_element lbre = new s3.ListBucketResponse_element();
        s3.ListBucketResult lbr = new s3.ListBucketResult();
        s3.ListAllMyBucketsList lambl = new s3.ListAllMyBucketsList();
        s3.metadataEntry me = new s3.metadataEntry();
        s3.ListAllMyBucketsEntry lambe = new s3.ListAllMyBucketsEntry();   
        s3.ListAllMyBucketsResult lambr = new s3.ListAllMyBucketsResult();
        s3.CreateBucketResult cbr = new s3.CreateBucketResult();
        s3.listEntry le = new s3.listEntry();
        //s3.DeleteObject_element  doe = new s3.DeleteObject_element();
        s3.CanonicalUser co = new s3.CanonicalUser();
        s3.DeleteBucketResponse_element dbr = new s3.DeleteBucketResponse_element();
        s3.PrefixEntry pe = new s3.PrefixEntry();
        s3.status status = new s3.status();
        s3.ListAllMyBucketsResponse_element labre = new s3.ListAllMyBucketsResponse_element();
        s3.CreateBucketResponse_element cbre = new s3.CreateBucketResponse_element();

        S3.AmazonS3 sss = new S3.AmazonS3(); 

        sss.DeleteObject( '','','',system.now(),'','');
    }

    static testmethod void test2() {
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

        S3.AmazonS3 sss = new S3.AmazonS3();
        sss.secret = '42';
        system.assert( sss.signature('encode',system.now() ) != null);
        sss.ListBucket( '','','', 3,'','key',system.now(),'sig','cred');    
    }

    static testmethod void test3() {
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        S3.ListAllMyBuckets('key',system.now(),'sig');
    }  

    static testmethod void test4() {
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        s3.AccessControlList acl = new s3.AccessControlList();
        S3.CreateBucket('bucket',acl,'key',system.now(),'sig');
    }  

    static testmethod void test5() {
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        S3.DeleteBucket('bucket','key',system.now(),'sig','cred');
    }  

    static testmethod void test6(){
        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.PutObjectInline_element putObjectElem = new S3.PutObjectInline_element();
        putObjectElem.Bucket='test';
        putObjectElem.Key = 'testKey';
        putObjectElem.Metadata = null;
        putObjectElem.Data= 'a';
        putObjectElem.ContentLength = 1;
        putObjectElem.AccessControlList = null;
        putObjectElem.StorageClass='classname';
        putObjectElem.AWSAccessKeyId='asdf';
        putObjectElem.Timestamp = Datetime.now();
        putObjectElem.Signature='test';
        putObjectElem.Credential='test'; 
    }

    static testmethod void test7(){

        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        try{
            S3.PutObjectInline_ACL('bucket','key',null,'datatesting',6,'public-read','keyid',System.now(),'sig','cred', 'ownerid') ;
        }catch(Exception ex){
        }
    }
}
3
  • Jose, Were you able to get this running ? I am running into a similar issue. Thanks!
    – Curt
    Jul 23 '14 at 17:20
  • Yes @Curt, I just followed Keith's answer. What's failing you?
    – Jose
    Jul 23 '14 at 17:51
  • Jose, Thanks for getting back with me so quickly, I think I have actually got it figured out Keith's solution did help.
    – Curt
    Jul 23 '14 at 18:08
2

By having:

Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

in each of your test methods, you are letting the test running framework know that you want the mock code invoked instead of the real web service callout code. So you have done all you need to there.

But I wonder how these tests ever passed? Perhaps someone with more history of the various Salesforce platform versions would know.

In general you would need your WebServiceMockImpl.doInvoke method to detect each of these requests and return the expected response objects (by inspecting the generated code for each one):

  • DeleteObject
  • ListBucket
  • ListAllMyBuckets
  • CreateBucket
  • DeleteBucket
  • PutObjectInline_ACL

But the tests do not assert anything about the responses so you should start by doing nothing and only add code as needed to avoid null pointer exceptions (again based on inspecting the code).

PS

Based on this Apex Web Services and Callouts page that uses s3 as an example, one of your operations looks like this (and you should be able to fins the others in the package code you have installed):

  public S3.Status DeleteObject(String Bucket,String Key,String AWSAccessKeyId,DateTime Timestamp,String Signature,String Credential) {
      S3.DeleteObject_element request_x = new S3.DeleteObject_element();
      S3.DeleteObjectResponse_element response_x;
      request_x.Bucket = Bucket;
      request_x.Key = Key;
      request_x.AWSAccessKeyId = AWSAccessKeyId;
      request_x.Timestamp = Timestamp;
      request_x.Signature = Signature;
      request_x.Credential = Credential;
      Map<String, S3.DeleteObjectResponse_element> response_map_x = new Map<String, S3.DeleteObjectResponse_element>();
      response_map_x.put('response_x', response_x);
      WebServiceCallout.invoke(
        this,
        request_x,
        response_map_x,
        new String[]{endpoint_x,
        '',
        'http://s3.amazonaws.com/doc/2006-03-01/',
        'DeleteObject',
        'http://s3.amazonaws.com/doc/2006-03-01/',
        'DeleteObjectResponse',
        'S3.DeleteObjectResponse_element'}
      );
      response_x = response_map_x.get('response_x');
      return response_x.DeleteObjectResponse;
  }

So to do a minimal job in your WebServiceMockImpl you would write it something like this, checking in the source code for things like how to construct a valid S3.Status object:

global void doInvoke(...) {
    if (request instanceof S3.DeleteObject_element) {
        S3.DeleteObjectResponse_element r = new S3.DeleteObjectResponse_element();
        r.DeleteObjectResponse = new S3.Status(...);
        response.put('response_x', r); 
    } else if (request instanceof ...) {
        ...
    }
}

As the tests don't assert anything about the responses you should need to do very little.

2
  • Hello, thanks for answering. I have not been able to make the WebServiceMockImpl.doInvoke method detect each of these requests and return the expected response objects. You mind guiding me a bit on how to do it?
    – Jose
    May 14 '14 at 14:14
  • @Jose I've added a PS to the answer with a rough outline of how to proceed. Good luck.
    – Keith C
    May 14 '14 at 16:00
1

As a supplement to Keith's answer, here is the code for the S3 and Mock files.

global class S3WebServiceMockImpl 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){
    if(request instanceof S3.DeleteBucket_element)
    {
        S3.DeleteBucketResponse_element r = new S3.DeleteBucketResponse_element();
        r.DeleteBucketResponse = new S3.Status();
        response.put('response_x', r); 
    }
    else if(request instanceof S3.DeleteObject_element)
    {
        S3.DeleteObjectResponse_element r = new S3.DeleteObjectResponse_element();
        r.DeleteObjectResponse = new S3.Status();
        response.put('response_x', r); 

    }
   else if(request instanceof S3.ListBucket_element)
    {
        S3.ListBucketResponse_element r = new S3.ListBucketResponse_element();
        r.ListBucketResponse = new S3.ListBucketResult();
        response.put('response_x', r); 

    }
      else if(request instanceof S3.ListAllMyBuckets_element)
    {
        S3.ListAllMyBucketsResponse_element r = new S3.ListAllMyBucketsResponse_element();
        r.ListAllMyBucketsResponse= new S3.ListAllMyBucketsResult();
        response.put('response_x', r); 

    }
    else if(request instanceof S3.CreateBucket_element)
    {
        S3.CreateBucketResponse_element r = new S3.CreateBucketResponse_element();
        r.CreateBucketResponse= new S3.CreateBucketResult();
        response.put('response_x', r); 

    }
   }
}









 public static testmethod void test1() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        s3.ListBucketResponse_element lbre = new s3.ListBucketResponse_element();
        s3.ListBucketResult lbr = new s3.ListBucketResult();
        s3.ListAllMyBucketsList lambl = new s3.ListAllMyBucketsList();
        s3.metadataEntry me = new s3.metadataEntry();
          s3.ListAllMyBucketsEntry lambe = new s3.ListAllMyBucketsEntry();   
        s3.ListAllMyBucketsResult lambr = new s3.ListAllMyBucketsResult();
        s3.CreateBucketResult cbr = new s3.CreateBucketResult();
        s3.listEntry le = new s3.listEntry();
        s3.DeleteObject_element  doe = new s3.DeleteObject_element();
        s3.CanonicalUser co = new s3.CanonicalUser();
        s3.DeleteBucketResponse_element dbr = new s3.DeleteBucketResponse_element();
        s3.PrefixEntry pe = new s3.PrefixEntry();
        s3.status status = new s3.status();
        s3.ListAllMyBucketsResponse_element labre = new s3.ListAllMyBucketsResponse_element();
        s3.CreateBucketResponse_element cbre = new s3.CreateBucketResponse_element();

        S3.AmazonS3 sss = new S3.AmazonS3(); 

        sss.DeleteObject( '','','',system.now(),'','');

   }

    public static testmethod void test2() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        S3.AmazonS3 sss = new S3.AmazonS3();
        sss.secret = '42';
        system.assert( sss.signature('encode',system.now() ) != null);
        sss.ListBucket( '','','', 3,'','key',system.now(),'sig','cred');    
    }

    public static testmethod void test3() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        S3.ListAllMyBuckets('key',system.now(),'sig');
    }  

    public static testmethod void test4() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        s3.AccessControlList acl = new s3.AccessControlList();
        S3.CreateBucket('bucket',acl,'key',system.now(),'sig');
    }  

    public static testmethod void test5() {
        Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
      S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        S3.DeleteBucket('bucket','key',system.now(),'sig','cred');
    }  

Here are the unit tests. The only thing you should have to add is Test.SetMock.

public static testmethod void test1() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        s3.ListBucketResponse_element lbre = new s3.ListBucketResponse_element();
        s3.ListBucketResult lbr = new s3.ListBucketResult();
        s3.ListAllMyBucketsList lambl = new s3.ListAllMyBucketsList();
        s3.metadataEntry me = new s3.metadataEntry();
          s3.ListAllMyBucketsEntry lambe = new s3.ListAllMyBucketsEntry();   
        s3.ListAllMyBucketsResult lambr = new s3.ListAllMyBucketsResult();
        s3.CreateBucketResult cbr = new s3.CreateBucketResult();
        s3.listEntry le = new s3.listEntry();
        s3.DeleteObject_element  doe = new s3.DeleteObject_element();
        s3.CanonicalUser co = new s3.CanonicalUser();
        s3.DeleteBucketResponse_element dbr = new s3.DeleteBucketResponse_element();
        s3.PrefixEntry pe = new s3.PrefixEntry();
        s3.status status = new s3.status();
        s3.ListAllMyBucketsResponse_element labre = new s3.ListAllMyBucketsResponse_element();
        s3.CreateBucketResponse_element cbre = new s3.CreateBucketResponse_element();

        S3.AmazonS3 sss = new S3.AmazonS3(); 

        sss.DeleteObject( '','','',system.now(),'','');

   }

    public static testmethod void test2() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        S3.AmazonS3 sss = new S3.AmazonS3();
        sss.secret = '42';
        system.assert( sss.signature('encode',system.now() ) != null);
        sss.ListBucket( '','','', 3,'','key',system.now(),'sig','cred');    
    }

    public static testmethod void test3() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        S3.ListAllMyBuckets('key',system.now(),'sig');
    }  

    public static testmethod void test4() {
      Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
        S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        s3.AccessControlList acl = new s3.AccessControlList();
        S3.CreateBucket('bucket',acl,'key',system.now(),'sig');
    }  

    public static testmethod void test5() {
        Test.setMock(WebServiceMock.class, new S3WebServiceMockImpl());
      S3.AmazonS3 S3 = new S3.AmazonS3();
        S3.secret = '42';
        system.assert( S3.signature('encode',system.now() ) != null);
        S3.DeleteBucket('bucket','key',system.now(),'sig','cred');
    }  

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.