Skip to main content
4 of 4
added 56 characters in body; edited title
Oscar Tang
  • 625
  • 7
  • 18

RestResponse does not return expected statuc code in Apex Rest unit test

Apex Rest returns 200 OK status code when directly access its Rest endpoint. However, in Apex Rest test class. RestResponse hooked in RestContext does not contains the status code (see below debug log).

Here is my test method. The containing class is also annotated with @isTest

@isTest
static void testCreateUser() {
    RestRequest req = new RestRequest();
    RestResponse res = new RestResponse();

    TestUtil.initTestData();

    User customerAdmin = [SELECT Id, AccountId FROM User WHERE username = '[email protected]'];

    String requestBody = '{ "firstName": "Test", "lastName": "Case 2", "email": "[email protected]" }';

    req.requestURI = URL.getSalesforceBaseUrl() + '/services/apexrest/MyId';
    req.httpMethod = 'POST';
    req.requestBody = Blob.valueOf(requestBody);

    Test.startTest();
    RestContext.request = req;
    RestContext.response = res;

    System.runAs(customerAdmin) {
        UserManagementRestController.createMyId();

        System.debug(req);
        System.debug(res);
    }
    
    Test.stopTest();
    // Something goes wrong here. No content in RestContext.response
    // Tempoary disable assertion on response
    //System.assertEquals(200, res.statusCode);

    List<User> users = [SELECT FirstName, LastName, Username, AccountId FROM User WHERE Email = '[email protected]'];
    System.assertEquals(1, users.size());

    User u = users[0];
    System.assertEquals('Test', u.FirstName);
    System.assertEquals('Case 2', u.LastName);
    System.assertEquals('[email protected]', u.Username);
    System.assertEquals(customerAdmin.AccountId, u.AccountId);
}

My Apex REST class:

@RestResource(urlMapping='/MyId/*')
global class UserManagementRestController {

    @HttpPost
    global static void createMyId() {
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;

        User requestUser = [SELECT Id, AccountId, Email FROM User WHERE Id = :UserInfo.getUserId()];

        // check if reqest user is customer admin
        Set<String> userPermissions = new Set<String>(UserPermissionRemoter.getUserPermission(requestUser.Id));
        if(!userPermissions.contains(UserPermissionMapper.customerAdminPermissionName)) {
            responseBadRequest('Only Customer Admin can perform this action', res);
            return;
        }

        MyId hid;
        try {
            hid = (MyId)JSON.deserialize(req.requestBody.toString(), MyId.class);
        } catch (JSONException e) {
            responseBadRequest(e.getMessage(), res);
            return;
        }
        System.debug('hid:');
        System.debug(hid);

        String email = hid.email;

        if(!isValidateEmail(email)) {
            responseBadRequest('Invalidate Email', res);
            return;
        }

        // check if new email is in the same domain with super user
        String[] splitEmail = email.split('@');
        String[] splitCurrentUserEmail = requestUser.Email.split('@');
        if(splitEmail[1].compareTo(splitCurrentUserEmail[1]) != 0) {
            responseBadRequest('Email domain mismatched. The new user email must have the same domain as the customer admin’s email.', res);
            return;
        }

        Savepoint createNewUserSavePoint = Database.setSavepoint();
        try {
            Contact newCt = new Contact();
            newCt.FirstName = hid.firstName;
            newCt.LastName = hid.lastName;
            newCt.Email = hid.email;
            newCt.AccountId = requestUser.AccountId;
            insert newCt;

            // Directly use corporate email
            String username = newCt.Email;

            // gen nickname
            DateTime currentTime = System.now();
            Long timeInMili = currentTime.getTime()/1000;
            String nickname = splitEmail[0]+timeInMili;

            // gen alias
            String alias = username;
            if(alias.length() > 8) {
                alias = alias.substring(0, 8);
            }

            User newUsr = new User();
            newUsr.FirstName = newCt.firstName;
            newUsr.LastName = newCt.lastName;
            newUsr.Email = newCt.email;
            newUsr.CommunityNickname = nickname;
            newUsr.profileId = getCommunityProfileId();
            newUsr.contactId = newCt.Id;
            newUsr.UserName = username;
            newUsr.Alias = alias;
            newUsr.TimeZoneSidKey = 'America/Los_Angeles';
            newUsr.LocaleSidKey = 'en_US';
            newUsr.EmailEncodingKey = 'ISO-8859-1';
            newUsr.LanguageLocaleKey = 'en_US';
            newUsr.IsActive = true;

            insert newUsr;
        } catch (system.Dmlexception e) {
            Database.rollback(createNewUserSavePoint);
            if(String.valueOf(e).contains('DUPLICATE_USERNAME')||String.valueOf(e).contains('DUPLICATE')){
                responseBadRequest('An account with this email already exists', res);
                return;
            }
            else{
                responseBadRequest(String.valueOf(e), res);
                return;
            }
        }
    }

    private static Boolean isValidateEmail(String email) {
        //Pattern p = Pattern.compile('^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$');
        //Matcher m = p.matcher(email);

        // according to SFDC support: https://help.salesforce.com/apex/HTViewSolution?id=000170904&language=en_US
        Pattern p = Pattern.compile('^[A-Z0-9._%+-/!#$%&\'*=?^_`{|}~]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$');
        Matcher m = p.matcher(email.toUpperCase());
        return m.matches();
    }

    private static Id getCommunityProfileId() {
        Profile p = [SELECT Id FROM Profile WHERE Name = 'My Customer Portal User' limit 1][0];
        return p.Id;
    }

    private static void responseBadRequest(String message, RestResponse res) {
        res.responseBody = Blob.valueOf(message);
        res.statusCode = 400;
        return;
    }

    public class MyId {
        public String firstName;
        public String lastName;
        public String email;

        public Boolean isCustomerAdmin;
        public Boolean isActive;
    }
}

In the debug log we can see the RestRequest is correctly set. However the RestResponse does not have any value in it. Would expect statusCode=200

21:56:59.902 (25902510196)|USER_DEBUG|[30]|DEBUG|RestRequest:[headers={}, httpMethod=POST, params={}, remoteAddress=null, requestBody=Blob[77], requestURI=Url:[delegate=http://cs1.salesforce.com]/services/apexrest/MyId, resourcePath=null]
21:56:59.902 (25902571034)|USER_DEBUG|[31]|DEBUG|RestResponse:[headers={}, responseBody=null, statusCode=null]

So what is the reason of getting different result from the test class and the actual Rest endpoint? Any way to test the exact behaviour of Apex Rest endpoint in a unit test class?

Oscar Tang
  • 625
  • 7
  • 18