When doing a callout it has to happen before the DML action. If it happens after the DML it will throw an error or will not execute. Workaround I used is to manually keep track of the mock response, and call the respond method to intercept Http.send when running a test. By checking for Test.isRunningTest() && (mock!=null) we can send the mock response.
Checking for test running and returning mock response
public static HttpCalloutMock mock = null; public HttpResponse callApiEndpoint(String apiEndpoint, String method, Object aPayload) { HttpRequest req = new HttpRequest(); try { if (apiEndpoint != null) { req.setTimeout(120000); req.setMethod(method); setAuthHeader(req); req.setEndpoint(WebCustomSettings.Heroku_API_URL__c + apiEndpoint); if (aPayload!=null) req.setBody(String.valueOf(aPayload)); System.debug('Sending api request to endpoint' + apiEndpoint); if (Test.isRunningTest() && (mock!=null)) { return mock.respond(req); } else { Http http = new Http(); return http.send(req); } } else { System.debug('Service apiEndpoint and payload must not be null'); throw new Rest_Exception(ResponseCodes_Mgr.getCode('HEROKU_REQUEST_CALLOUT_FAILED')); } } catch (Exception ex) { System.debug('ERROR sending sync request to Heroku: ' + ex); List<String> theArgs = new List<String>(); theArgs.add('Api'); theArgs.add(req.getEndpoint()); throw new Rest_Exception(ResponseCodes_Mgr.getCode('HEROKU_REQUEST_CALLOUT_FAILED', ex, theArgs)); } }
Test class
Test.startTest(); System.runAs(new User(Id=userWithAccountContact.get('UserId'))){ //Setting the mock variable and it's also a test so will return the mock response Heroku_Services_Api.mock = new Heroku_Services_Api_Mock(200, 'Complete', '{}',null); req.requestBody = Blob.valueOf('{"id":"'+ account.Id +'", "clientId":"' + userWithAccountContact.get('ContactId') + '", "amount":122233,"endDate":"2022-01-01"}'); req.requestURI = '/v1/account'; req.httpMethod = 'PATCH'; RestContext.request = req; RestContext.response = res; try{ Rest_Dispatcher.doPatch(); } catch(Rest_Exception ex){ System.assertEquals(ex.itsRespCode.formattedSystemMessage, 'blah'); } System.assert(res.responseBody!=null); System.assertEquals(res.statusCode, 200); } Test.stopTest();