[SalesForce] How to do code coverage for Catch Block:

Below is my apex class:

public void submitForApproval(List<Account> acc)
{

    try{

        for(SObject ac :acc) {

            if((ac.Account_Record_Type_Name__c == 'A' || ac.Account_Record_Type_Name__c == 'B') &&  ac.Status__c == 'New'){
                // Create an approval request for the Account
                Approval.ProcessSubmitRequest submitRequest = new Approval.ProcessSubmitRequest();
                submitRequest.setComments('Submitting request for approval');
                submitRequest.setObjectId(ac.id);
                submitRequest.setSubmitterId(ac.CreatedById); 
                submitRequest.setProcessDefinitionNameOrId('Account for Approval');           
                Approval.ProcessResult result = Approval.process(submitRequest);    
                system.debug('Result ' + result.isSuccess() + 'NewObj ID' + ac.Id);
            }
        }

    }catch(Exception ex){
        system.debug('Exception in Approval Process submision and error is--->'+ex);

        Batch.trackErrorLog(CLASS_NAME, 'submitForApproval',
                                    'Exception Line Number:' + ex.getLineNo() +
                                    'Exception Type' + ex.getType()+                                                             
                                    'Exception Message' + ex.getmessage());
    }

}

I tried to write a test class like this:

Account testdelAcc=new Account(Name = 'Test DelAcc');

try{
    testdelAcc.RecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('ABC').getRecordTypeId();
    insert testdelAcc;
}
catch(Exception e)
{
    system.assertEquals(e.getMessage(), e.getMessage());
}

I am trying to pass Invalid Record Type but it does not cover the catch block.
Can someone help me what I am missing here?

Best Answer

The way you have written test method logic, it will never enter in catch block as in your main class you are not throwing an exception when recordtype is Invalid.

submitForApproval method will throw the exception if system is unable to process the submit for approval.

You can change your code as below if possible.

Approach 1

Pass processDefinitionNameOrId as an argument to this method

public void submitForApproval(List<Account> acc, String processDefinitionNameOrId)
{

    try{

        for(SObject ac :acc) {

            if((ac.Account_Record_Type_Name__c == 'A' || ac.Account_Record_Type_Name__c == 'B') &&  ac.Status__c == 'New'){
                // Create an approval request for the Account
                Approval.ProcessSubmitRequest submitRequest = new Approval.ProcessSubmitRequest();
                submitRequest.setComments('Submitting request for approval');
                submitRequest.setObjectId(ac.id);
                submitRequest.setSubmitterId(ac.CreatedById); 
                submitRequest.setProcessDefinitionNameOrId(processDefinitionNameOrId);           
                Approval.ProcessResult result = Approval.process(submitRequest);    
                system.debug('Result ' + result.isSuccess() + 'NewObj ID' + ac.Id);
            }
        }

    }catch(Exception ex){
        system.debug('Exception in Approval Process submision and error is--->'+ex);

        PSABatchUtil.trackErrorLogs(CLASS_NAME, 'submitForApproval',
                                    'Exception Line Number:' + ex.getLineNo() +
                                    'Exception Type' + ex.getType()+                                                             
                                    'Exception Message' + ex.getmessage());
    }
}

Test Class

From the test method, pass invalid process definition Id for which System will throw the exception.

One more point, your assert statement. What you are trying to compare with the assertEquals() when you are putting both expected output in both the arguments.

Follow best practices writing test class.

Account testdelAcc=new Account(Name = 'Test DelAcc');

YourClass cls = new YourClass();

    insert testdelAcc;
    List<Account> lstAccount = new List<Account>();
    lstAccount.add(testdelAcc);
    cls.submitForApproval(lstAccount, 'any invalid processDefinitionNameOrId');
   //check any values create in PSABatchUtil.trackErrorLogs 

Approach 2

Without changing method signature, you could declare a variable for processDefinitionNameOrId

@TestVisible private String processDefinitionNameOrId = 'Account for Approval' ;

public void submitForApproval(List<Account> acc)
{

    try{

        for(SObject ac :acc) {

            if((ac.Account_Record_Type_Name__c == 'A' || ac.Account_Record_Type_Name__c == 'B') &&  ac.Status__c == 'New'){
                // Create an approval request for the Account
                Approval.ProcessSubmitRequest submitRequest = new Approval.ProcessSubmitRequest();
                submitRequest.setComments('Submitting request for approval');
                submitRequest.setObjectId(ac.id);
                submitRequest.setSubmitterId(ac.CreatedById); 
                submitRequest.setProcessDefinitionNameOrId(processDefinitionNameOrId);           
                Approval.ProcessResult result = Approval.process(submitRequest);    
                system.debug('Result ' + result.isSuccess() + 'NewObj ID' + ac.Id);
            }
        }

    }catch(Exception ex){
        system.debug('Exception in Approval Process submision and error is--->'+ex);

        PSABatchUtil.trackErrorLogs(CLASS_NAME, 'submitForApproval',
                                    'Exception Line Number:' + ex.getLineNo() +
                                    'Exception Type' + ex.getType()+                                                             
                                    'Exception Message' + ex.getmessage());
    }
}

Test class

Assign any invalid values from test class to processDefinitionNameOrId.

Account testdelAcc=new Account(Name = 'Test DelAcc');

YourClass cls = new YourClass();

    insert testdelAcc;
    List<Account> lstAccount = new List<Account>();
    lstAccount.add(testdelAcc);
    cls.processDefinitionNameOrId = 'any invalid processDefinitionNameOrId';
    cls.submitForApproval(lstAccount);
    //check any values create in PSABatchUtil.trackErrorLogs 
}
Related Topic