I ran into something similar to what you're describing here. I had all data setup in a testSetup
method and committed no DML's in between Test.startTest()
and Test.stopTest()
, just querying a record and passing that to the data to a web service.
I also confirmed that there were no fresh DML statements by adding a Limits.getDMLStatements()
right before the call out, it returned 0. I have scoured the boards and this is the best example that's similar to the behavior I have run into.
I'm certain it's a bug on the Salesforce side, and unfortunately those can take a while to resolve and I need to have this deployed! I came up with a workaround, and I wanted to share it since it may save you (if you're still having the issue) or someone else a lot of misery!
In my mock class that I was calling during the test, I had my sample JSON responses defined as static strings. So I did a tweaked version of a response built in to the call out:
//This is one of the callout functions that I'm using to hit a REST API
global HttpResponse getAllTemplates() {
HttpRequest req = setupBaseRequest(null);
req.setEndpoint(baseEndPoint+'/templates');
req.setMethod('GET');
HttpResponse res;
if (Test.isRunningTest()) {
res = new HttpResponse();
res.setBody(MyMockClass.templateExampleJSON);
res.setStatusCode(200);
res.setStatus('OK');
}
if (!Test.isRunningTest()) res = new Http().send(req);
return res;
}
Here is my mock class (example only):
@isTest
global class MyMockClass implements HttpCalloutMock {
global static String templateExampleJSON = '{"templateName":"TestName","TemplateId":"12345"}';
global HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
res.setStatusCode(200);
res.setStatus('OK');
if (req.getEndPoint().contains('/templates')) {
res.setBody(templateExampleJSON);
} else {
res.setStatusCode(400);
res.setStatus('Bad Request');
}
return res;
}
Doing it this way allows my test class to fire correctly. It also allows the actual response to go out when it's not testing. I feel like it's a little bit of a hack; however, it accomplishes my end goal of testing the functionality.
There are four approaches to avoiding this issue
- Update the testmethods to include the necessary data that the PBs require (Phil W's suggestion)
- Update the PBs to do a better job of testing for the absence of related objects so they don't blow up
- Gate the PBs with a custom setting that you enable in your testmethods to turn off the PBs for those testmethods where you are having this issue
- Rework your testmethods and code to use dependency injection and mocking. This is well covered in Force.com Enterprise Architecture 2nd Edition by Andrew Fawcett, now VP at SFDC. This approach means you can avoid doing DML in your testmethods and hence the PBs won't execute. It is great for unit testing.
In our org, we use a combination of 1 (some), 2 (definitely) and 4 (most definitely)
Best Answer
It's not a complete answer but you can always rollback dml operations yourself:
You will still have the problem of callouts and emails being sent, but if these are not a factor it will be sufficient