I have a PUT method that I am attempting to test, but, like usual, APEX's ridiculous restrictions are causing roadblocks at every turn I make. My put method works fine when I am calling it from Postman or some live client, but I need to write some tests in SF for the class before going to production.

In my tests, I would like to test what happens in the response. Did it respond with a 200 status code? Did it respond with the correct error? etc. But for some APEX reason it doesn't allow me to return HttpResponse, and I can't figure out how I can write the test to actually test the response.

Here is my PUT method:

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

    try {
        // Get Request
        Map<String, Object> requestBody = (Map<String, Object>)JSON.deserializeUntyped(req.requestBody.toString());


        // Parse request body
        List<Object> newRoleIds = (List<Object>)requestBody.get('roles');
        Integer studentId = Integer.valueOf(requestBody.get('studentId'));

        // Check request body
        String errorString = '';
        Boolean errored = false;
        if (studentId == null) {
            errorString += '\'studentId\' not provided\n';
            errored = true;
        if (errored) {
            res.responseBody = Blob.valueOf(errorString);
            res.statusCode = 422;

        // Query db for needed data
        Student__c student = [SELECT Id FROM Student__c WHERE drupalId__c = :studentId];
        List<Role__c> allRoles = [SELECT Id, drupalId__c FROM Role__c];

        // Delete Previous records
        delete [SELECT Id, Role__c FROM StudentRoleRelationship__c WHERE Student__c = :student.Id];

        // Create new records
        List<StudentRoleRelationship__c> newRelationships = new List<StudentRoleRelationship__c>();
        for (Object newRoleId : newRoleIds) {
            for (Role__c role : allRoles) {
                if ((Integer)newRoleId == role.drupalId__c) {
                    StudentRoleRelationship__c studentRoleRelationship = new StudentRoleRelationship__c();
                    studentRoleRelationship.Role__c = role.Id;
                    studentRoleRelationship.Student__c = student.Id;
                    insert studentRoleRelationship;

        // Add Response
        res.responseBody = Blob.valueOf(String.valueOf(newRelationships));
        res.statusCode = 200;
    } catch (Exception e) {
        // Error
        res.responseBody = Blob.valueOf(e.getMessage());
        res.statusCode = 500;

Here is my test method:

static void setup() {

 * UpdateStudentRoles
public class UpdateBody {
    public String studentId;
    public List<Integer> roles;

public class MockUpdateStudentRolesHttpResponse implements HttpCalloutMock {
    public HTTPResponse respond(HTTPRequest req) {
        HttpResponse res = new HttpResponse();
        return res;

static void put_updateStudentRoleRelationships() {

    // Get and set the needed information
    List<Student__c> studentRecs = [SELECT id FROM Student__c LIMIT 1];
    List<Role__c> roleRecs = [SELECT drupalId__c FROM Role__c LIMIT 1];
    String studentId = studentRecs[0].Id;
    Integer roleId = (Integer)roleRecs[0].drupalId__c;

    // Prepare Request  
    RestRequest req  = new RestRequest();
    RestResponse res = new RestResponse();

    req.requestURI = '/services/apexrest/YTPStudentRolesController';
    req.httpMethod = 'PUT';

    UpdateBody body = new UpdateBody();
    body.studentId = studentRecs[0].Id;
    body.roles = new List<Integer>();
    String jsonBody = JSON.serialize(body);
    req.requestBody = Blob.valueOf(jsonBody);

    RestContext.request = req;
    RestContext.response = res;

    // Test
    Test.setMock(HttpCalloutMock.class, new MockUpdateStudentRolesHttpResponse());

Right now, this test returns as successful even though the response returns with an error. How can I actually run Asserts on the response from a put method?!?!


Test the method by calling it directly, not using a callout. Make sure you set the RestContext variables as they will be null otherwise.

RestContext.request = new RestRequest();
RestContext.response = new RestResponse();

  • Agree with Adrian. I'd even take it a step further and extract the business logic out of the method so you can call the logic without needing an HttpRequest. It's by design that Salesforce doesn't allow call-outs from tests. – Mike Lockett Jan 27 at 20:35
  • You don't need to extract it to a separate method to remove the need for an HttpRequest. You can call the method via Apex with no callout required. – Adrian Larson Jan 27 at 20:37
  • Agree, you don't have to. updateStudentRoleRelationships gets roleIds and studentId from the request object. I would have an updateStudentRoleRelationships that takes roleIds and studentId as parameters which would be called by the @HttpPut method. Then it could be called from other places as well. – Mike Lockett Jan 27 at 20:48

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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