1

I am stuck in the test class for the Transaction Finalizer class. Every time when we create an exception for Queueable class then Finalizer class executing and then the test class throws the error on the test method and also not handled by try catch.

Below is my Queueable class Sample code:

public class QueueableClass implements Queueable {

    public void execute (QueueableContext context) {

    QueueableFinalizer finalizer = new QueueableFinalizer();
    System.attachFinalizer(finalizer);

   // Below code will failed Queueable because of System.LimitException: Too many DML 
   // statements: 151 And then Finalizer class will be Executes.

     if(Test.isRunningTest()){

     while (true) { // results in limit error
            Account a = new Account();
            a.Name = 'Account-Number-';
            insert a;
        }
         }
           }

Below is my Finalizer class Sample code:

   public class QueueableFinalizer implements Finalizer{

         public void execute(FinalizerContext ctx) { 
    
    // here we rerun the Queueable by using the system.Queueable
            
}
}

Below is my Test class Sample code for Finalizer:

   public static testMethod void testToFailQueueable() {

   test.startTest();
    try{
        System.enqueueJob(new QueueableClass ());  // here Too many DML Statement Error Occur.
        
    }catch(Exception e){
        
    }
    test.stopTest();
         
  
  }

Please suggest to me how to implement the test class for Finalizer. Thank you!

3
  • 1
    Since you can rely on the infrastructure to function correctly - there really isn't a need to unit test this - you could instead simply and explicitly test the finaliser implementation behaviour using an explicit call to its execute method from a separate test. BTW by separating out the finaliser into a separate class, instead of having a class that impleme to both the quueable and finaliser, you lose access to the queueable's state. Additionally the keyword testMethod is deprecated, replaced years ago by @isTest.
    – Phil W
    Commented Dec 28, 2021 at 9:13
  • 1
    (My guess is that the test infrastructure doesn't handle governor limit issues and finalizers properly. This would not be the first bug in the testing infrastructure around async processing)
    – Phil W
    Commented Dec 28, 2021 at 9:15
  • @Philw Yeah we can explicitly call to its execute method from a separate test but it doesn't test our Finalizer requirement. We want to Assert the First and last Error from the finalizer. Commented Dec 28, 2021 at 9:38

1 Answer 1

4

Since Async operations run in Sync manner inside test.startTest and test.stopTest().

You wont be able to capture LimitException with a try catch.

No need to test unhandled exceptions from test class. In documentation its mentioned that no matter what happens Finalizer will get called. So you can rest assure that it will get called.

Better throw a DML Exception when a test is running and test finalizer as LimitExceptions cannot be caught.

Test Class:

@IsTest
static void testLimitFinalizer() {
    try {
        Test.startTest();
        System.enqueueJob(new QueueableClassLimit());
        Test.stopTest();
    } catch (Exception e){
        System.debug(e);
    }
}

public class QueueableClassLimit implements Queueable {

    public void execute(QueueableContext context) {

        QueueableFinalizer finalizer = new QueueableFinalizer();
        System.attachFinalizer(finalizer);

        // Below code will failed Queueable because of System.LimitException: Too many DML
        // statements: 151 And then Finalizer class will be Executes.

        if (Test.isRunningTest()) {

            throw new DmlException('Test My Finalizer');
        }
    }
}

public class QueueableFinalizer implements Finalizer{

    public void execute(FinalizerContext ctx) {

        System.debug('Test Finalizer');

    }
}

Test class passes:

enter image description here

10
  • 2
    You make a good point, actually.
    – sfdcfox
    Commented Dec 28, 2021 at 9:38
  • The finalizer execution should still happen when the limit error is thrown, though it must be said the limit exception still terminates the original transaction so, yeah, the exception should still happen and, yeah, use a cashable exception in this (integration) testing context.
    – Phil W
    Commented Dec 28, 2021 at 10:00
  • Yes correct, finalizer will execute even from test context. Commented Dec 28, 2021 at 10:02
  • I added the below DML Exception code in Queueable class: if(test.isRunningTest()){ Account a = new Account(); insert a; } But still, the exception is thrown on the test method. test.startTest(); try{ System.enqueueJob(new OpportunityCloseQueueable(testOppUpdateMap, testOppList)); }catch(Exception e){ } test.stopTest(); Commented Dec 28, 2021 at 10:04
  • Again as suggested by @sfdcfox you will have to put your try catch differently. See my above example. Commented Dec 28, 2021 at 10:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .