Skip to content

Instantly share code, notes, and snippets.

@abhinavguptas
Created September 24, 2011 03:05

Revisions

  1. Abhinav Gupta revised this gist Sep 24, 2011. 3 changed files with 87 additions and 0 deletions.
    29 changes: 29 additions & 0 deletions AWS.java
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,32 @@
    /*
    Copyright (c) 2011 tgerm.com
    All rights reserved.
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. The name of the author may not be used to endorse or promote products
    derived from this software without specific prior written permission.
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */


    public with sharing class AWS {
    /**
    Handle to easily switch between natural HTTP callout and Mock Callouts for test cases.
    29 changes: 29 additions & 0 deletions Test_AWS.java
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,32 @@
    /*
    Copyright (c) 2011 tgerm.com
    All rights reserved.
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. The name of the author may not be used to endorse or promote products
    derived from this software without specific prior written permission.
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */


    @isTest
    private class Test_AWS {
    /**
    29 changes: 29 additions & 0 deletions WS.java
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,32 @@
    /*
    Copyright (c) 2011 tgerm.com
    All rights reserved.
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. The name of the author may not be used to endorse or promote products
    derived from this software without specific prior written permission.
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */


    /**
    Collection of classes/interfaces for creating a fixture that will ease the Testing effort with webservices.
    */
  2. Abhinav Gupta revised this gist Sep 24, 2011. 2 changed files with 56 additions and 53 deletions.
    44 changes: 2 additions & 42 deletions Test_AWS.java
    Original file line number Diff line number Diff line change
    @@ -1,51 +1,11 @@
    @isTest
    private class Test_AWS {
    /**
    Indicator for operation being accessed is virtual as of now.
    */
    public class VirtualOperationException extends Exception {}

    /**
    Meant to be base/parent class for Apex test case simulations.
    Its a mock implementation of IHttpResponse, it gives a virtual body
    of all contract methods in IHttpResponse, and throws VirtualOperationException
    for every method call. Using this class as parent, subclasses would be easy i.e. just
    override the methods required, instead of implementing the whole IHttpResponse contract.
    For ex. in most of the cases, one will override getStatusCode() and getBody() for testing purposes.
    */
    public virtual class MockHttpResponseBase implements WS.IHttpResponse {
    public virtual String getBody() {
    throw new VirtualOperationException('No implementation available !');
    }
    public Dom.Document getBodyDocument() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getHeader(String key) {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String[] getHeaderKeys() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getStatus() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Integer getStatusCode() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Xmlstreamreader getXmlStreamReader() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String toStrings() {
    throw new VirtualOperationException('No implementation available !');
    }
    }

    /**
    /**
    Please note we have extended WS.MockHttpResponseBase
    instead of implementing ws.IHttpResponse, because we want to
    override three methods only
    */
    public class MockHttpResponse extends MockHttpResponseBase {
    public class MockHttpResponse extends WS.MockHttpResponseBase {
    public String body;
    public String status;
    public Integer statusCode;
    65 changes: 54 additions & 11 deletions WS.java
    Original file line number Diff line number Diff line change
    @@ -29,6 +29,19 @@ public interface IHttpResponse {
    String toStrings();
    }

    /**
    Contract for a simple web service callout using Apex.
    Only a single method is available for abstracting the stuff out for ease of Testing.
    Test classes can provide implmentations of this interface to return custom/fake/mock HTTP responses.
    */
    public interface IHttpCallout {
    /**
    Accepts a ready to send requests and makes a callout using that.
    */
    IHttpResponse send(HttpRequest req);
    }


    /**
    Default wrapper implementation over standard Apex HttpResponse class.
    Reference : http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_httpresponse.htm
    @@ -74,17 +87,6 @@ public String toStrings() {
    }
    }

    /**
    Contract for a simple web service callout using Apex.
    Only a single method is available for abstracting the stuff out for ease of Testing.
    Test classes can provide implmentations of this interface to return custom/fake/mock HTTP responses.
    */
    public interface IHttpCallout {
    /**
    Accepts a ready to send requests and makes a callout using that.
    */
    IHttpResponse send(HttpRequest req);
    }

    /**
    Default implementation meant for use in actual apex code. It runs out of
    @@ -96,4 +98,45 @@ public IHttpResponse send(HttpRequest req) {
    return new DefHttpResponse(http.send(req));
    }
    }


    /**
    Indicator for operation being accessed is virtual as of now.
    */
    public class VirtualOperationException extends Exception {}

    /**
    Meant to be base/parent class for Apex test case simulations.
    Its a mock implementation of IHttpResponse, it gives a virtual body
    of all contract methods in IHttpResponse, and throws VirtualOperationException
    for every method call. Using this class as parent, subclasses would be easy i.e. just
    override the methods required, instead of implementing the whole IHttpResponse contract.
    For ex. in most of the cases, one will override getStatusCode() and getBody() for testing purposes.
    */
    public virtual class MockHttpResponseBase implements IHttpResponse {
    public virtual String getBody() {
    throw new VirtualOperationException('No implementation available !');
    }
    public Dom.Document getBodyDocument() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getHeader(String key) {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String[] getHeaderKeys() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getStatus() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Integer getStatusCode() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Xmlstreamreader getXmlStreamReader() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String toStrings() {
    throw new VirtualOperationException('No implementation available !');
    }
    }
    }
  3. Abhinav Gupta revised this gist Sep 24, 2011. 2 changed files with 41 additions and 41 deletions.
    42 changes: 41 additions & 1 deletion Test_AWS.java
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,51 @@
    @isTest
    private class Test_AWS {
    /**
    Indicator for operation being accessed is virtual as of now.
    */
    public class VirtualOperationException extends Exception {}

    /**
    Meant to be base/parent class for Apex test case simulations.
    Its a mock implementation of IHttpResponse, it gives a virtual body
    of all contract methods in IHttpResponse, and throws VirtualOperationException
    for every method call. Using this class as parent, subclasses would be easy i.e. just
    override the methods required, instead of implementing the whole IHttpResponse contract.
    For ex. in most of the cases, one will override getStatusCode() and getBody() for testing purposes.
    */
    public virtual class MockHttpResponseBase implements WS.IHttpResponse {
    public virtual String getBody() {
    throw new VirtualOperationException('No implementation available !');
    }
    public Dom.Document getBodyDocument() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getHeader(String key) {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String[] getHeaderKeys() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getStatus() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Integer getStatusCode() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Xmlstreamreader getXmlStreamReader() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String toStrings() {
    throw new VirtualOperationException('No implementation available !');
    }
    }

    /**
    Please note we have extended WS.MockHttpResponseBase
    instead of implementing ws.IHttpResponse, because we want to
    override three methods only
    */
    public class MockHttpResponse extends WS.MockHttpResponseBase {
    public class MockHttpResponse extends MockHttpResponseBase {
    public String body;
    public String status;
    public Integer statusCode;
    40 changes: 0 additions & 40 deletions WS.java
    Original file line number Diff line number Diff line change
    @@ -29,46 +29,6 @@ public interface IHttpResponse {
    String toStrings();
    }

    /**
    Indicator for operation being accessed is virtual as of now.
    */
    public class VirtualOperationException extends Exception {}

    /**
    Meant to be base/parent class for Apex test case simulations.
    Its a mock implementation of IHttpResponse, it gives a virtual body
    of all contract methods in IHttpResponse, and throws VirtualOperationException
    for every method call. Using this class as parent, subclasses would be easy i.e. just
    override the methods required, instead of implementing the whole IHttpResponse contract.
    For ex. in most of the cases, one will override getStatusCode() and getBody() for testing purposes.
    */
    public virtual class MockHttpResponseBase implements IHttpResponse {
    public virtual String getBody() {
    throw new VirtualOperationException('No implementation available !');
    }
    public Dom.Document getBodyDocument() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getHeader(String key) {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String[] getHeaderKeys() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getStatus() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Integer getStatusCode() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Xmlstreamreader getXmlStreamReader() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String toStrings() {
    throw new VirtualOperationException('No implementation available !');
    }
    }

    /**
    Default wrapper implementation over standard Apex HttpResponse class.
    Reference : http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_httpresponse.htm
  4. Abhinav Gupta revised this gist Sep 24, 2011. No changes.
  5. Abhinav Gupta renamed this gist Sep 24, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  6. Abhinav Gupta revised this gist Sep 24, 2011. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion Test_AWS.java
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@

    @isTest
    private class Test_AWS {
    /**
  7. Abhinav Gupta revised this gist Sep 24, 2011. 2 changed files with 132 additions and 0 deletions.
    60 changes: 60 additions & 0 deletions AWS.Java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    public with sharing class AWS {
    /**
    Handle to easily switch between natural HTTP callout and Mock Callouts for test cases.
    Those who love patterns, can use Factory if required to achieve the same. But I find
    it really handy in test cases to change.
    for ex. My test code can just replace the IHttpCallout impl as:
    AWS.CALLOUT = new MockAWSCallout();
    Here MockAWSCallout is a fake implementation that will simulate HTTP callout for sake of test cases.
    */
    public static WS.IHttpCallout CALLOUT = new WS.DefHttpCallout();


    public String serviceEndPoint = '<SET IT HERE>';
    public String bucket = '<SET IT HERE>';
    public String key = '<SET IT HERE>';
    /*
    Example AWS callout code taken from this awesome WIKI page :
    http://wiki.developerforce.com/index.php/Apex_Web_Services_and_Callouts
    Please Note: this method is just for illustration purpose, not ready to be used as it is.
    */
    public void store(String body) {

    HttpRequest req = new HttpRequest();
    //Set HTTPRequest Method
    req.setMethod('PUT');
    //Set HTTPRequest header properties
    req.setHeader('content-type', 'image/gif');
    req.setHeader('Content-Length','1024');
    req.setHeader('Host','s3.amazonaws.com');
    req.setHeader('Connection','keep-alive');
    req.setEndpoint( this.serviceEndPoint + this.bucket +'/' + this.key);
    //Set the HTTPRequest body
    req.setBody(body);

    try {

    //Execute web service call here
    //
    // PLEASE NOTE : here we have used the static variable
    // CALLOUT here
    //
    WS.IHttpResponse res = CALLOUT.send(req);

    //Helpful debug messages
    System.debug('STATUS:'+res.getStatus());
    System.debug('STATUS_CODE:'+res.getStatusCode());

    /// Do what else is biz requirement with the response.
    // ...
    //.....
    //

    } catch(System.CalloutException e) {
    //Exception handling goes here....
    }
    }

    }
    72 changes: 72 additions & 0 deletions Test_AWS.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,72 @@

    @isTest
    private class Test_AWS {
    /**
    Please note we have extended WS.MockHttpResponseBase
    instead of implementing ws.IHttpResponse, because we want to
    override three methods only
    */
    public class MockHttpResponse extends WS.MockHttpResponseBase {
    public String body;
    public String status;
    public Integer statusCode;

    public MockHttpResponse(String body, String status, Integer statusCode) {
    this.body = body;
    this.status = status;
    this.statusCode = statusCode;
    }

    public override String getBody() {
    return body;
    }

    public override String getStatus() {
    return status;
    }

    public override Integer getStatusCode() {
    return statusCode;
    }
    }

    /**
    Mock Callout Implementation
    */
    public class MockHttpCallout implements WS.IHttpCallout {
    private MockHttpResponse resp;

    public WS.IHttpResponse send(HttpRequest req) {
    return resp;
    }

    /**
    This method was not part of original WS.IHttpCallout contract
    as its one of the way test case can pass mock response to it.
    */
    public void setResponse(MockHttpResponse resp) {
    this.resp = resp;
    }
    }

    /*
    A test call to the store method in AWS class
    */
    static testMethod void testStoreCall() {
    MockHttpCallout mockCallout = new MockHttpCallout();
    // Tell AWS Apex class to use Mock Callout instead of this one
    AWS.CALLOUT = mockCallout;

    AWS amazon = new AWS();
    // create a mock XML response you want the actual code to parse
    MockHttpResponse mockResp = new MockHttpResponse('<xml..> some xml response body', 'OK', 200);
    // tell callout to return this response when a request comes
    mockCallout.setResponse(mockResp);

    amazon.store('My Cool Body to preserve in Amazon S3 :)');
    // Please do some assertions
    //
    System.assertEquals('Some Good Asserts here', 'No good asserts, writing those will be out of scope for this illustration');
    //
    }
    }
  8. Abhinav Gupta revised this gist Sep 24, 2011. No changes.
  9. Abhinav Gupta renamed this gist Sep 24, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  10. Abhinav Gupta created this gist Sep 24, 2011.
    139 changes: 139 additions & 0 deletions WS.cls
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,139 @@
    /**
    Collection of classes/interfaces for creating a fixture that will ease the Testing effort with webservices.
    */
    public with sharing class WS {
    /**
    Contract for HTTPResponse. To avoid learning and confusions this interface is exposing
    all the methods available in Apex HTTPResponse class(http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_httpresponse.htm)
    Test classes can override and implement them as required
    */
    public interface IHttpResponse {

    String getBody();

    Dom.Document getBodyDocument();

    String getHeader(String key);

    String[] getHeaderKeys();

    String getStatus();

    Integer getStatusCode();

    Xmlstreamreader getXmlStreamReader();

    // have to name it toStrings() instead of toString(), as the later
    // is reserved by Apex
    String toStrings();
    }

    /**
    Indicator for operation being accessed is virtual as of now.
    */
    public class VirtualOperationException extends Exception {}

    /**
    Meant to be base/parent class for Apex test case simulations.
    Its a mock implementation of IHttpResponse, it gives a virtual body
    of all contract methods in IHttpResponse, and throws VirtualOperationException
    for every method call. Using this class as parent, subclasses would be easy i.e. just
    override the methods required, instead of implementing the whole IHttpResponse contract.
    For ex. in most of the cases, one will override getStatusCode() and getBody() for testing purposes.
    */
    public virtual class MockHttpResponseBase implements IHttpResponse {
    public virtual String getBody() {
    throw new VirtualOperationException('No implementation available !');
    }
    public Dom.Document getBodyDocument() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getHeader(String key) {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String[] getHeaderKeys() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String getStatus() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Integer getStatusCode() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual Xmlstreamreader getXmlStreamReader() {
    throw new VirtualOperationException('No implementation available !');
    }
    public virtual String toStrings() {
    throw new VirtualOperationException('No implementation available !');
    }
    }

    /**
    Default wrapper implementation over standard Apex HttpResponse class.
    Reference : http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_httpresponse.htm
    All contract methods of IHttpResponse are delegated to the wrapped Apex HttpResponse instance.
    */
    public virtual class DefHttpResponse implements IHttpResponse {
    public Httpresponse resp;

    public DefHttpResponse(HttpResponse resp) {
    this.resp = resp;
    }

    public String getBody() {
    return resp.getBody();
    }

    public Dom.Document getBodyDocument() {
    return resp.getBodyDocument();
    }

    public String getHeader(String key) {
    return resp.getHeader(key);
    }

    public String[] getHeaderKeys() {
    return resp.getHeaderKeys();
    }

    public String getStatus() {
    return resp.getStatus();
    }

    public Integer getStatusCode() {
    return resp.getStatusCode();
    }

    public Xmlstreamreader getXmlStreamReader() {
    return resp.getXmlStreamReader();
    }

    public String toStrings() {
    return resp.toString();
    }
    }

    /**
    Contract for a simple web service callout using Apex.
    Only a single method is available for abstracting the stuff out for ease of Testing.
    Test classes can provide implmentations of this interface to return custom/fake/mock HTTP responses.
    */
    public interface IHttpCallout {
    /**
    Accepts a ready to send requests and makes a callout using that.
    */
    IHttpResponse send(HttpRequest req);
    }

    /**
    Default implementation meant for use in actual apex code. It runs out of
    standard Apex Http Class (http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_http.htm)
    */
    public class DefHttpCallout implements IHttpCallout {
    public IHttpResponse send(HttpRequest req) {
    Http http = new Http();
    return new DefHttpResponse(http.send(req));
    }
    }
    }