0

I have an OnInsert trigger is firing a queueable apex that makes a REST API callout. The entire code is in a try/catch block. In the catch block, the code is sending an email, updating an exception log custom object and creates a ticket with our support ticketing system.

A sample piece of code is below.

trigger customProductTrigger on customProduct__c (after insert) {
    try {
        if (Trigger.isInsert && Trigger.isAfter) {
            List<String> lstProductStrings = new List<String>();
            for (CustomProduct__c cpr : Trigger.new) {
                lstProductStrings.add(cpr.Count+';'+cpr.ProductId+';'+cpr.productName+';'+cpr.eventType);
            }
        }
        system.enqueueJob(new CustomProductServices());
    } catch (Exception ex) {
        ** if (!Test.isRunningTest()) { **
            ///// Send Email using Messaging class
            ///// Insert records into ExceptionLog custom object
            ///// Create a ticket with supporting system via a REST API 
        }
    }
}

My guess was by putting the Test.isRunningTest() in the exception code, we don't need to worry about covering this piece of code. However, when I run the test class, the code inside the Exception code is showing as "not covered" and the code coverage is less than 75% only.

Can someone help on how I can exclude the code in the exception block to be skipped for code coverage calculation?

2
  • 1
    Instead of trying to cover the catch block, you should probably just remove the try/catch altogether. The only exceptions you could run into here are limit exceptions (which are uncatchable). You should also be using a trigger framework so you can keep your logic out of your trigger.
    – Derek F
    Commented Nov 29, 2022 at 16:14
  • You have misunderstood Test.isRunningTest. It does not delimit lines that should not be considered part of test coverage, but instead allows you to avoid executing certain lines of code during execution of a test. I recommend against such approaches in general since it means you are not actually fully testing your production code and have different behaviour under test. This is bad practice. Only use this if absolutely essential (e.g. if you haven't structured your code to allow dependency injection and you need to avoid sending an email).
    – Phil W
    Commented Nov 29, 2022 at 16:27

1 Answer 1

1

My guess was by putting the Test.isRunningTest() in the exception code, we don't need to worry about covering this piece of code.

Wrong. Any code not in a class annotated with @isTest requires coverage. There are no exceptions, not even using Test methods like isRunningTest. You'll need to find a way to cover your code, e.g. by throwing an exception somehow. It's usually better to move exception handling logic to its own method so you can test it independently without sacrificing a lot of code coverage.

In other words:

} catch (Exception ex) {
  Utils.handleException(ex);
}

This way, you can test the email logic in a separate test, and even if you can't actually generate an exception, you now only lose one line of coverage instead of 10-20.

Also, make sure the try-catch is actually necessary, and try to minimize the try-catch logic to just methods that can actually throw exceptions, rather than the entire block. Remember you may also need to use SavePoint and Database.rollback. Finally, keep in mind that if you're sending an email, you have to allow the (possibly bad) data to persist to the database, because errors would rollback the email as well.

1
  • Thanks for your response. I will try moving the exception handling code into it's own method and also implement the other suggestions. Commented Dec 1, 2022 at 0:58

You must log in to answer this question.

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