1

Controller method:

 @AuraEnabled
 public static customObject__c getInfo(String recordId){
    try {
        customObject__c rec = new customObject__c ();
        
        List<customObject__c > sobjList = Database.query('Select id from customObject__c where id=:recordId');
        if(!sobjList.isEmpty()){
            rec = sobjList[0];
        }
        return rec;
    } catch (Exception e) {
        throw new AuraHandledException(e.getMessage());
    }
}

Test method:

@isTest
static void testGetInfoFailure(){
    Test.startTest();
    try{
        CustomClass.getInfo('123');
        System.assert(false, 'Expected an exception.');
    } catch(AuraHandledException e) {
        System.debug('AuraHandledException: ' +e.getMessage());
        System.assert(false, e.getMessage());
    }
    Test.stopTest();
}

I have followed the approach from this answer but looks like I am still unable to cover the catch block with AuraHandledException.

3
  • 1
    Do note that system.assert(false, 'optional message'); will always fail. Such a thing should not appear in the assertion in your catch block. The reason it's ok to have it in the try block is that when you are specifically testing that an exception is thrown, you'll only reach that assertion in the case where the exception is not thrown. That's the failure condition for your test, so it's ok (desireable, even) for that assertion to fail at that point. It's a compact but arguably less readable approach.
    – Derek F
    Jul 27 at 19:08
  • 1
    P.S. You should use the correct data type for your parameter (Id, not String), and second, you need to understand when it's possible for a query to throw an exception. Rather than write your code to throw an exception that will never come, just remove the try-catch altogether.
    – sfdcfox
    Jul 27 at 20:45
  • @sfdcfox That make total sense why my catch block is not being executed even with invalid data. I will consider your recommendations.
    – Arnold Jr.
    Jul 27 at 22:12
3

Testing exceptions is hard (well, harder than testing most other things).

The reason why you're not catching an exception is because an exception isn't being generated. If you provide a nonsense value for an Id in a query via a variable bind, you'll just get 0 rows as a result rather than an exception (that goes for both normal and dynamic SOQL queries).

Unless there's something I'm missing with your method being @auraEnabled, there doesn't seem to be a reason for you to make that query dynamic.

Probably the easiest way to get your test to throw the exception you want would be to store the result of your query in a single SObject instance (instead of in a List). That would, however, interfere with you returning a new SObject instance in the case where you don't find an existing instance.

In this case, I don't think there's much utility in specifically writing a test to cover the catch block outside of getting 75% coverage. If you can add one more line of executable code before you return, you shouldn't need to cover the catch block (if my interpretation of executable lines is right).

Beyond that, when it's very difficult (or impossible) to cause an exception to be thrown, I've included a private static Boolean (test visible) to control when an exception should be thrown like so

public class MyClass{
    // private so that other people can't mess around with it
    // testVisible so that we can mess around with it in test contexts
    @testVisible
    private static Boolean throwException = false;

    public void doWork(){
        try{
            if(MyClass.throwException){
                throw new Exception();
            }
        }catch(Exception e){
            // notify of the exception, or do some work, or re-throw
            // empty catch blocks are a red flag (do you really need to catch the
            //   exception in that case?)
        }
    }
}
@isTest
private class MyClassTest{
    @isTest
    static void runNormal(){
        new MyClass().doWork();
    }

    @isTest
    static void runException(){
        MyClass.throwException = true;

        try{
            new MyClass.doWork();
            system.assert(false, 'Should have thrown an exception');
        }catch(MyException e){
            system.assert(e.getMessage().contains('a fragment of your exception message'), 'Exception message was wrong');
        }
    }
}

Perhaps not the most elegant approach, but it'll work. The fun part is that if you add in that code to be able to control when exceptions are thrown, you may add enough executable lines that you won't have to cover the catch block.

5
  • OP is why adopting service/selector/domain/unit of work pattern yields benefits as you can, with mocking framework like apexMocks or amoss, mock the object and have it return an exception to test the caller. But moving to this pattern only comes with experience
    – cropredy
    Jul 27 at 19:36
  • @cropredy is there a design pattern(s) I can learn? I am a developer, but still trying to improve my potential. Any recommendations would really appreciated.
    – Arnold Jr.
    Jul 27 at 19:44
  • @DerekF - I was able to cover my class with 100% coverage. To use custom exceptions, I had to use/extend the built-in Exception class as referred here.
    – Arnold Jr.
    Jul 27 at 19:46
  • 1
    @ArnoldJr. - Check out the Lightning Enterprise Architecture 3rd edition book by Andrew Fawcett - eye-opening
    – cropredy
    Jul 27 at 20:40
  • +1 I would argue that there should be no try-catch here. Since it's impossible for the query to fail, there's nothing to catch. Never build for an exception that can never occur.
    – sfdcfox
    Jul 27 at 20:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.