function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Sachin10Sachin10 

Callout loop not allowed in Test Class

Hi,
I have a trigger and a class which implements a queueable interface.
When a record gets created the trigger invokes the queueable interface which will make a callout.

Now I'm writing the test class for the same.
In the test class I'm setting the mock response using httpMockCallout and inserting the record.
But I'm getting an exception, Callout loop not allowed.
Any Idea why this is happening?

As a workaround I set the response using test.Isrunningtest and it works fine.

Any pointers would be helpful.
Many Thanks
andy81andy81
I believe the "System.CalloutException: Callout loop not allowed" CalloutException is intended to stop one synchronous Apex transaction from calling out to another Salesforce hosted web service.

The work around for this was to switch to an asynchronous context such as batch or a future method. 
Sachin10Sachin10
Thanks for your reply.
I'm getting the exception only from the testClass.
The functionality is working fine.

And even in test class, if I set the response using test.IsRunningTest it's not throwing any exception.
But when I use HttpMockCallout to set the response, the test class is throwing the exception.

Just trying to understand why it is happening in this case alone.

 
andy81andy81
Hope this kind of annotations would help you to guide through test class. 

HttpRequest request = new HttpRequest();
        StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
        mock.setStaticResource('googlejson');
        mock.setStatusCode(200);
        mock.setHeader('Content-Type', 'application/json');
        mock.respond(request);
        Test.setMock(HttpCalloutMock.class, mock);
Amit Chaudhary 8Amit Chaudhary 8
Hi Sachin10

For this please use Moke Class :-
Moke Test Class
@isTest
global class MockHttpResponseGenerator implements HttpCalloutMock 
{
    global HTTPResponse respond(HTTPRequest req) 
    {
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody('{"foo":"bar"}');
        res.setStatusCode(200);
        return res;
    }
}



Some usefull link :-
https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_testing_httpcalloutmock.htm
https://developer.salesforce.com/forums/ForumsMain?id=906F00000009AObIAM
http://salesforce.stackexchange.com/questions/4988/writing-test-classes-for-apex-restservice
http://blog.jeffdouglas.com/2012/03/21/writing-unit-tests-for-v24-apex-rest-services/
http://cloudyworlds.blogspot.in/2012/12/writing-test-classes-for-apex-rest.html

Please mark this as solution by selecting it as best answer if this solves your problem, So that if anyone has this issue this post can help
Sachin10Sachin10
@andy81: Thanks for your reply.I tried it, But didn't work. Still the same exception.

@Amit: I'm doing the same.Infact the same approach works in other cases where callout is made from a normal apex class.
            Here the callout is made from a class that implements Queueable interface.

The functionality works fine.
For some reason the respond method is not getting invoked from Testclass.
An exception 'Callout Loop not allowed' is coming when I run the testClass.
Trying to understand why this is happening.

 
Sachin10Sachin10
Thanks for your reply.
The functionality is: When I create a record, a callout has to be made, which is working fine.
But the response is not getting set in Test Class
Here is the pseudo code

//MY TRIGGER
trigger myObjectTrigger on myObject__c(after insert){
    if(trigger.isInsert && trigger.isAfter)
    System.enqueueJob(new myQueueable(trigger.new));
}

//MY APEX CLASS
public class myQueueable implements Queueable, Database.AllowsCallouts {
    
    //Constructor
    public myQueueable(list<myObject__c>myObjList){
    }

    //Execute method
    public void execute(QueueableContext context) {
        Callout to the external system is made here
    }

}

//MY TEST CLASS
public class myTestCls {

    static testmethod void testCalloutSuccess() {
        Test.startTest();       
        Test.setMock(HttpCalloutMock.class, 
        new CalloutMockTest(201,'{"abc_id": "a0231", "def_id": 513917}'));
        insert acq;
        Test.stopTest();
    }
    
}

//MY MOCK CALLOUT CLASS
@isTest
public class CalloutMockTest implements HttpCalloutMock {

    protected Integer code;    
    protected String body;
    

    public CalloutMockTest(Integer code, String body) {
        this.code = code;        
        this.body = body;   
        system.debug('@@ in CalloutMockTest constructor body'+body);    
    }

    public HTTPResponse respond(HTTPRequest req) {
         system.debug('@@ in CalloutMockTest req'+req);        
        
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody(body);
        res.setStatusCode(code);
        system.debug('@@ in calloutMock res'+res);
        return res;
    }

}
Ruben Carvalho 10Ruben Carvalho 10
Any luck with this issue? I'm facing the exact same thing at the moment.

Basically, a Queueable job can make callouts without any errors but if you run the job synchronously inside Test.startTest()/Test.stopTest() it throws a callout exception.

Thanks
Seb OrtizSeb Ortiz
I'm facing the same issue when unit testing a Queueable job which makes a callout to an external service. Using a mock class too.

Any solution?
Fred BFred B
This is a known bug in Salesforce.
https://success.salesforce.com/issues_view?id=a1p30000000sXtbAAE

As a workaround for now I don't do the callout from the queable class if a test is running.
Not the best solution as I can't fully test my code.

    if(Test.isRunningTest()==false) //Do the callout