function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Jannis BottJannis Bott 

Unit Test for Twilio Restful Webservice

Hi all,

I have implemented an SMS service from Twilio that can handle incoming messages. I have pretty much followed this awesome video from Pat Patterson.

I am struggling to write a test class that passes the Twilio request validation. Can anybody please help me out and show how to do it? 

Here is my class:
@RestResource(urlMapping='/TwilioRecruitment')
global class TwilioRecruitment {
    static TwilioAccount account = TwilioAPI.getDefaultAccount();
    
    @future(callout=true)
    public static void reply(string fromNumber, string toNumber, string message){
        Map<String, String> params = new Map<String, String> {
            'From' => fromNumber,
            'To' => toNumber,
            'Body' => message
        };
        
        TwilioSms sms = account.getSmsMessages().create(params);
        system.debug('Send SMS SId' +  ' ' + sms.getSid());
    }
    
    @HttpPost
    global static void incomingSMS() {
        
        String expectedSignature = 
            RestContext.request.headers.get('X-Twilio-Signature');
            system.debug('expectedSignature ' + expectedSignature);
        String url = 'https://' + RestContext.request.headers.get('Host') + 
            '/services/apexrest' + RestContext.request.requestURI;
            system.debug('url ' + url);
        Map <String, String> params = RestContext.request.params;
        system.debug('params ' + params);
        system.debug('TwilioAPI.getDefaultClient().validateRequest(expectedSignature, url, params) ' + TwilioAPI.getDefaultClient().validateRequest(expectedSignature, url, params));
        // Validate signature
        if (!TwilioAPI.getDefaultClient().validateRequest(expectedSignature, url, params)) {
            RestContext.response.statusCode = 403;
            RestContext.response.responseBody = 
                Blob.valueOf('Failure! Rcvd '+expectedSignature+'\nURL '+url);
            return;
        } 
        
        //Twilio to check if something is in the response body otherwise report
        // a 502 error in https://twilio.com/account/log/notifications
        
        RestContext.response.responseBody = Blob.valueOf('ok');
        
        //Extract useful fields from the incoming SMS
        String senderNumber = params.get('From');
        String receiver = params.get('To');
        String body = params.get('Body');
        system.debug('From, To, Body' + ' ' + senderNumber + ' ' + receiver + ' ' + body);
        //Try find matching TFP employee
        TFP_Employee__c tfpEmpl = null;
        try{
            String prefixAU = '+61';
            String formattedSenderNumber = '';
            if(senderNumber.startsWith(prefixAU)){
                formattedSenderNumber = 0 + senderNumber.removeStart(prefixAU);
            }
           ... More logic below here...

This is the test class that fails at the validation:
@isTest
global class TwilioRecruitmentTest {

    static testMethod void testGet() {

        RestRequest req = new RestRequest(); 
        RestResponse res = new RestResponse();
        
        req.requestURI = '/services/apexrest/TwilioRecruitment';
        req.httpMethod = 'POST';

        req.addParameter('From','+61458883222');
        req.addParameter('Body','This is a test');
        req.addParameter('To','+61437879336');
        req.addParameter('ToCountry','AU');
        req.addParameter('ToState','');
        req.addParameter('SmsMessageSid','SMS MESSAGE ID HERE ');
        req.addParameter('NumMedia','0');
        req.addParameter('ToCity','');
        req.addParameter('FromZip','');
        req.addParameter('SmsSid','SMS ID HERE');
        req.addParameter('SmsStatus','received');
        req.addParameter('FromCity','');
        req.addParameter('FromCountry','AU');
        req.addParameter('ToZip','');
        req.addParameter('MessageSid','MESSAGE SID HERE');
        req.addParameter('AccountSid','ACCOUNT SID HERE');
        req.addParameter('ApiVersion','2010-04-01');

        req.httpMethod = 'POST';
        RestContext.request = req;
        RestContext.response = res;
        
        TwilioRecruitment.incomingSMS();
        
    }
}

Any help would be awesome!
Thanks!
Akhil MehraAkhil Mehra
You need to write Mock .

@IsTest(SeeAllData=true)
public class MockClassGenerator implements HttpCalloutMock {
        public HTTPResponse respond(HTTPRequest req){ 
            HttpResponse response = new HttpResponse();
             if(req.getEndpoint().contains('https://api.twilio.com/2010-04-01/Accounts/AC7e95462c0dee71ef032344e19a722d70/Messages.json'))
             {
         
                    response.setBody('{"sid": "SM41f757ba73bb4085a3db2fa42f173ebe", "date_created": "Mon, 17 Apr 2017 15:57:35 +0000", "date_updated": "Mon, 17 Apr 2017 15:57:35 +0000", "date_sent": null, "account_sid": "AC7e95462c0dee71ef032344e19a722d70", "to": "+16198055452", "from": "+16195667694", "messaging_service_sid": null, "body": "nj,dnznxhzkjhkxc", "status": "queued", "num_segments": "1", "num_media": "0", "direction": "outbound-api", "api_version": "2010-04-01", "price": null, "price_unit": "USD", "error_code": null, "error_message": null, "uri": "/2010-04-01/Accounts/AC7e95462c0dee71ef032344e19a722d70/Messages/SM41f757ba73bb4085a3db2fa42f173ebe.json", "subresource_uris": {"media": "/2010-04-01/Accounts/AC7e95462c0dee71ef032344e19a722d70/Messages/SM41f757ba73bb4085a3db2fa42f173ebe/Media.json"}}'); 
                   response.setHeader('Content-Type', 'application/json');
                        response.setStatusCode(200);
             }
                else
                {    
                     response.setBody('{"sid": "SM41f757ba73bb4085a3db2fa42f173ebe", "date_created": "Mon, 17 Apr 2017 15:57:35 +0000", "date_updated": "Mon, 17 Apr 2017 15:57:35 +0000", "date_sent": null, "account_sid": "AC7e95462c0dee71ef032344e19a722d70", "to": "+16198055452", "from": "+16195667694", "messaging_service_sid": null, "body": "nj,dnznxhzkjhkxc", "status": "queued", "num_segments": "1", "num_media": "0", "direction": "outbound-api", "api_version": "2010-04-01", "price": null, "price_unit": "USD", "error_code": null, "error_message": null, "uri": "/2010-04-01/Accounts/AC7e95462c0dee71ef032344e19a722d70/Messages/SM41f757ba73bb4085a3db2fa42f173ebe.json", "subresource_uris": {"media": "/2010-04-01/Accounts/AC7e95462c0dee71ef032344e19a722d70/Messages/SM41f757ba73bb4085a3db2fa42f173ebe/Media.json"}}'); 
                       response.setHeader('Content-Type', 'application/json');
                        response.setStatusCode(400); 
                }
            return response;
            }
        

    }