UnitTestException: Maximum stack depth has been reached_Trigger Test class

apexqueueable-apexunit-test

I have 2 queueable classes and i have chained them in my account update trigger

the logic is like below

Trigger Logic- onAccountUpdate

{

Queueableclass1 que1 = new Queueableclass1(newList);
System.enqueue(que1);

}

Queueable class 1

Execute()
{
Some Logic…

Queueableclass2 que2 = new Queueableclass2(newList);
System.enqueue(que2);

}

in Testclass

I have created the Account test data and made an update to test this scenario. But the it is throwing maximum depth reached error as it is trying to execute both jobs in same test method.

So I understand that I cannot run 2 async jobs from one method. Can Somebody please suggest me that how can I fix my trigger test class..?

Best Answer

So, you can't test chained queueables at depth more than 1 in a testmethod

There are multiple parts to the answer

Gate all your System.enqueue with a reference to a Utility property

public static Boolean   isEnqueueable {
    get {
        return isEnqueueable == null 
          ? Limits.getLimitQueueableJobs() - Limits.getQueueableJobs() > 0 
          : isEnqueueable;
    } set;
}

e.g.

if (Util.isEnqueueable) {System.enqueueJob(..);}
else { // fallback logic}

you can dependency inject the value of Util.isEnqueueable = false to control in testmethods whether to enqueue a queueable job

Break your problem into two unit tests:

  • Unit test 1 - Does the trigger invoke the first queueable?
  • Unit test 2 - does the first queueable invoke the second queueable?

For the first unit test

  • set Util.isEnqueueable = false;

  • DML the record in the testmethod

  • assert that there is an AsyncApexJob for the queueable class 1

    // given mock record
    Sobject sobj = new (Account(..);
    // given queueables disabled
    Util.isEnqueueable = false;
    // when inserted
    insert sobj;
    // then verify asyncapexjob exists for the expected queueable
    system.assert([SELECT Id FROM AsyncApexJob WHERE ApexClass.Name = 'MyFirstQueueable'].size() == 1,'sb queueable apex scheduled');
    

For the second unit test

  • Construct an object of the first queueable

  • Then invoke its execute() method

  • Assert that the second queueable (called by the first) does what it is supposed to do)

    // Given object of first queueable
    MyFirstQueueable qc1 = new MyFirstQueueable(..);
    // when it executes
    qc1.execute(null);
    // verify second queueable called and it does its work
    System.assert(..); 
    
Related Topic