[SalesForce] System.AsyncException: Maximum stack depth has been reached

I have two Queueable classes, I am trying to execute them by chaining them.
First approach was to calling second queueable from first class.

But, it gives me System.AsyncException: Maximum stack depth has been reached. error in test class.

My Apex classes version is 40.0

Class 1:

public with sharing class QueueableClass1 implements Queueable{
    public QueueableClass1(){}

    public void execute(QueueableContext context){}
}

Class 2:

public with sharing class QueueableClass2 implements Queueable{
    public QueueableClass2(){}
    public void execute(QueueableContext context){}
}

Method:
The following execution works, but I am looking for chaining queueable jobs.

public void processQueues(){
    System.enqueueJob(new QueueableClass1());
    System.enqueueJob(new QueueableClass2());
}

Below code gives "System.AsyncException: Maximum stack depth has been reached." error in test class.

public with sharing class QueueableClass1 implements Queueable{
    public QueueableClass1(){}

    public void execute(QueueableContext context){
        System.enqueueJob(new QueueableClass2());    
    }
}

Test Class: The test class has following syntax.

@isTest
public class MyClass_Test {

    @testSetup
    static void createData(){
        // created sample data       
    }
    
    static testMethod void test_processQueues() {
        
        Test.startTest();
        MyClass obj = new MyClass();
        obj.processQueues(); // This method consist of first Queueable Job. And Second Job has been chained into the first job
        Test.stopTest();
    }
}

Just wanted to know, Am I doing anything wrong here? I am looking for execution of second class when first class has finished its operation.

Best Answer

The next lines on salesforce documentation about Queueable interface say the following

You can’t chain queueable jobs in an Apex test. Doing so results in an error. To avoid getting an error, you can check if Apex is running in test context by calling Test.isRunningTest() before chaining jobs.

So to test funcionality you can simulate chaining:

QueueableClass1 first = new QueueableClass1();
first.execute(null);
//Asserts go here
QueueableClass2 second = new QueueableClass2();
second.execute(null);
//Asserts go here

Do not run code above between Test.startTest() and Test.stopTest(), as this will cause to do a try of chaining second class (and this will result in error)

according to Adrian's suggestion about Test.isRunningTest() add testvisible Boolean field, that allow you to have flexible control of behavior of class:

public with sharing class QueueableClass1 implements Queueable{
    @testVisible
    private static Boolean doChainJob = true;

    public QueueableClass1(){}

    public void execute(QueueableContext context){
        if(doChainJob) {
            System.enqueueJob(new QueueableClass2());    
        }
    }
}

Then to test it without Test.isRunningTest()

@isTest
static void testFirstQueueable(){
    QueueableClass1.doChainJob = false;
    Test.startTest();
        System.enqueueJob(new QueueableClass1());
    Test.stopTest();
    //Asserts goes here
}
Related Topic