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?