You need to sign in to do that
Don't have an account?

Error When only send a HttpCallout in batch request
hi i am sending only a single Http Request in Batch but still facing error System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out
My test code is
@isTest(SeeAllData=true)
static void test1(){
MirrorTestUtil.setupSettings();
User u = [Select Authorize__c From User Where Id = :UserInfo.getUserId()];
u.Authorize__c = true;
update u;
System.debug('u is '+u);
List<FeedItem> feedList= new List<FeedItem>();
for (Integer i = 0; i<5;i++)
feedList.add( new FeedItem(Body='@'+UserInfo.getName()+'Hello World'+i,ParentId = UserInfo.getUserId()));
Test.setMock(HttpCalloutMock.class, new MirrorMockTimelinePostImpl());
Test.startTest();
Test.setMock(HttpCalloutMock.class, new MirrorMockTimelinePostImpl());
insert feedList;
Test.stopTest();
}
and My trigger code is
trigger PostFeedsToTimeLine on FeedItem (after insert) {
BatchPublishTimeLine publishBatch = new BatchPublishTimeLine(Trigger.new,contentMap);
Database.executeBatch(publishBatch,5);
}
and My Batch class code is
public class BatchPublishTimeLine implements Database.Batchable<sObject>{
sObjectIterable iterable;
Map<Id,User> userMap;
Map<String,String> contentmap;
public BatchPublishTimeLine(List<sObject> objectList,Map<String,String> contentmap){
iterable = new sObjectIterable(objectList);
this.userMap = new Map<Id,User>([Select Id,Name From User WHERE Authorize__c = true]);
this.contentmap = contentmap;
}
public Iterable<sObject> start(Database.BatchableContext BC){
return iterable;
}
public void execute(Database.BatchableContext BC, List<sObject> scope){
GMirrorUtil.createTimeLine(scope, contentMap);
}
public void finish(Database.BatchableContext BC){
System.debug('Job Has been Finished');
}
}
and My createTimeLine function code is
public static void createTimeLine(List<sObject> objList,Map<String,String> contentMap){
String timelineRes = doApiCall('xyzzz','POST','https://www.googleapis.com/mirror/v1/timeline','xxxxxxxxx');
}
doApiCall code is
public static String doAPICall(String postBody, String method, String endPoint, String accessToken){
HttpRequest req = new HttpRequest();
Http http = new Http();
HttpResponse res;
req.setEndpoint(endPoint);
req.setMethod(method);
req.setHeader('Content-Type','application/json');
if(method == 'POST' || method == 'PUT')
req.setBody(postBody);
req.setHeader('Authorization','Bearer ' + accessToken);
res = http.send(req);
String result = res.getBody();
System.debug('status code is '+res.getStatus());
System.debug('result is'+res.getBody());
return result;
}
and the Mock class code response is
@isTest
global class MirrorMockTimelinePostImpl implements HTTPCalloutMock {
global HTTPResponse respond(HTTPRequest req) {
// Optionally, only send a mock response for a specific endpoint
// and method.
System.assertEquals('https://www.googleapis.com/mirror/v1/timeline', req.getEndpoint());
System.assertEquals('POST', req.getMethod());
System.assert(req.getHeader('Authorization').startsWith('Bearer'));
// Create a fake response
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('{"kind":"mirror#timelineItem", "id":"mockid", "created":"2013-07-31T12:07:34.882Z", "updated":"2013-07-31T12:07:34.882Z", "etag":"\\"ZECOuWdXUAqVdpmYErDm2-91GmY/NVMWuR8LJyCKttsmne9R4K8n7YI\\"", "text": "New Lead: OauthCheck EarlyAm, Google, Inc., (234) 567-8900"}');
res.setStatusCode(200);
return res;
}
}
and i am unable to figure it out how using only one callout its throwing an error ?? Please help
have in your test meathod have to be out side your start test
stop test block .refer winter 13 release notes
for testing webservice callouts.
http://boards.developerforce.com/t5/Apex-Code-Development/Testing-Webservice-Callouts-with-Winter-13-Test-setMock-fails/td-p/510427/page/3
Hi Ritesh,
The way you built this code needs to be refactored a bit. You need to split your test class to test the Trigger Separately and the Batch Class separately.
Just try to test the batch class that is doing the callout by passing the FeedItem list to test your Http & Batch.
and as mentioned by Salesforce Hidden Facts, try inserting the test data (feeditems ) before the StartTest() and then set the mock inside the Test.StartTest() and then call your Batch Class.
Also, I noticed that you are not implementing Database.AllowCallouts in your actual Batch Class. Please do that otherwise it will throw you an error.
Tip: to control when to execute triggers try using a static boolean variable.
Thank you
Kartik
ok i implemented Database.Allowscallouts .Is there any thing wrong if trigger calls the Batch apex ?? if i do nothing when test is running ok thats work but i think it should also work when trigger executes batch apex.
There is nothing wrong if trigger calls Batch Class, but the problem is that you are inserting the record after you setMock and inside Test.startTest(),
"The rule with Callouts is you cannot do a DML Operation before any Callouts", its been like this since beginning. Just to allow users to get around this, Salesforce implemented a rule saying that in Test Class if you are testing callout , insert all your data before starting the test. So for your test to run insert the data before Test.startTest(). But since you have a trigger that fires on Insert - there is no way you can insert without firing batch/callout causing the same problem you've had. So control your trigger execution and write tests accordingly.
If you still have issues, let me know and I will send you some sample code.
Thanks a lot for the help but see the code below.My Test code function is this
@isTest(SeeAllData=true)
static void test1(){
MirrorTestUtil.setupSettings();
User u = [Select Authorize__c From User Where Id = :UserInfo.getUserId()];
u.Authorize__c = true;
update u;
System.debug('u is '+u);
List<FeedItem> feedList= new List<FeedItem>();
for (Integer i = 0; i<5;i++)
feedList.add( new FeedItem(Body='@'+UserInfo.getName()+'Hello World'+i,ParentId = UserInfo.getUserId()));
insert feedList;
String xx='%@'+UserInfo.getName()+'%';
feedList = [Select Body,CreatedById From FeedItem Where ParentId = :UserInfo.getUserId()];
for(Integer i=0;i< feedList.size();i++){
System.debug('List is'+feedList);
System.debug('item is '+feedList.get(i) +' i is'+ i);
if( !(feedList.get(i).Body == null) && (!feedList.get(i).Body.contains('@'+UserInfo.getName())))
{feedList.remove(i);
i--;}
}
System.debug('size is '+feedList.size());
Integer i= 2;
if(feedList.size() >2)
while(feedList.size() >2)
feedList.remove(i);
System.debug('size is '+feedList);
Map<String,String> contentMap = new Map<String,String>{'Object' =>'FeedItem','Content' =>'Body'};
Test.startTest();
BatchPublishTimeLine time1 = new BatchPublishTimeLine(feedList,contentMap);
Database.executeBatch(time1,5);
Test.stopTest();
}
and my batch apex is same as above but my createTimeline function is
public static void createTimeLine(List<sObject> objList,Map<String,String> contentMap){
if(Test.isRunningTest())
Test.setMock(HttpCalloutMock.class, new MirrorMockTimelinePostImpl());
String timelineRes = doApiCall('xyzzz','POST','https://www.googleapis.com/mirror/v1/timeline','xxxxxxxxx');
}
and doApiCall function is same as above but i changed trigger for some time to this
trigger PostFeedsToTimeLine on FeedItem (after insert) {
Map<String,String> contentMap = new Map<String,String>{'Object' =>'FeedItem','Content' =>'Body'};
if(Trigger.new.size() >= 5){
BatchPublishTimeLine publishBatch = new BatchPublishTimeLine(Trigger.new,contentMap);
// Database.executeBatch(publishBatch,5);
}
// else GMirrorUtil.createTimeLine(Trigger.new, contentMap);
}
but when i run my test case still i am getting the same error
System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out
according to your suggestion it should not show this error .please give reply.
Ok. I think there is still a bug with the DML executing a Trigger and then doing a callout.
Can you try commenting out the //insert feedList and run your test class. It worked for me. The other DMLs are working fine (UPDATE User) its just the ones that have Triggers defined are causing issue.