[SalesForce] Apex Trigger catch block can’t be covered by test class

I have a trigger named AssignsCanadaWebLeadtoQueueOnLanguage on our Stage instance which according to Developer Console has lines within a catch block which I can't seem to cover using my test class named TestAssignsCaWebLeadtoQueueOnLanguage.

I specifically tried to test the exception within the AssignsCanadaWebLeadtoQueueOnLanguage_Exception_Test method within my test class. I've tried throwing a new custom Exception. I've tried creating an Exception scenario by creating a Lead and then inserting it without setting any required field values.

However, I can't seem to get these catch lines to be covered by this method. I read that there is the possibility of lines that can't be covered at all.

Is this one of those situations? If not, how can I move forward and get the lines within my catch block for this trigger covered by my test class method?

trigger AssignsCanadaWebLeadtoQueueOnLanguage on Lead (before insert) 
{
    // Purpose: This trigger was written as part of a fix for an issue where multiple notification emails 
    //          were being sent to members of a particular queue after a Canada Web Lead was created. 
    //          Only one email was needed. 
    // This trigger is meant to replace two workflow rules:
    //          " - Assigns Web Lead to English Queue on Language" and
    //          "- Assigns Web Lead to French Queue on Language"
    try
    {
        string strEnglishQueue = Label.CanadianEnglishWebLeadQueue;
        string strFrenchQueue = Label.CanadianFrenchWebLeadQueue;

        User mqUser = [Select id from User where Alias = 'jaffa'];        
        Group gEnglish = [Select Id From Group where Name = :strEnglishQueue AND Type = 'Queue'];    
        Group gFrench = [Select Id From Group where Name = :strFrenchQueue AND Type = 'Queue'];

        for(Lead l : trigger.new) 
        {    

            // We only want to address Canada Web Leads.  These leads are defined as 
            // leads where the owner is the MQ Broker user
            if (l.OwnerID == mqUser.id) 
            {                
                l.LeadSource = Label.CanadianWebLeadSource;

                // Change Lead Owner to appropriate queue based on language
                if(l.LA_Language__c == 'English')
                {
                    l.OwnerID = gEnglish.id;
                }
                if(l.LA_Language__c == 'French')
                {
                    l.OwnerID = gFrench.id;                 
                }                                            
            }            
        }          
    }
    catch (Exception e)
    {
        String SourceRecords='Lead Id: ';
        for (Integer i=0; i < Trigger.size; i++)
        {
            SourceRecords = SourceRecords+';'+Trigger.new[i].Get('Id');
        }

        String HTMLEmailBody = 'A Web Lead has been created in Salesforce.com  with the following exception in the AssignsCanadaWebLeadtoQueueOnLanguage trigger:<br><br> ' +
        'Error: ' + e.getMessage() + ' <br><br>' + e.getStackTraceString() + ' <br><br>' +
        SourceRecords  + '</a>';

        String recipients = Label.CandaWebLeadsExceptionEmailList;
        String[] toAddresses = new String[]{};
        toAddresses = recipients.split(',');

        EmailAsync.sendEmailAsync(toAddresses,Label.CandaWebLeadsExceptionEmailList,'Salesforce Web Lead Exception',
        'A Web Lead has been created in Salesforce.com with an Exception',
        false, false,'A Web Lead has been created in Salesforce.com  with the following exception in the AssignsCanadaWebLeadtoQueueOnLanguage trigger',
        HTMLEmailBody);
    }                  
}

**************test class *****************

@isTest
private class TestAssignsCaWebLeadtoQueueOnLanguage 
{    
    static testMethod void AssignsCanadaWebLeadtoQueueOnLanguage_English_Test()
    {
        test.StartTest();
        Group newGroup = TestFactory.returnGroupbyName('Canada Web Leads - English');

        Campaign newCampaign = TestFactory.buildTestCampaign('TestCampaign');
        insert newCampaign;        

        User u = TestFactory.returnUserByAlias('tycoismq'); 

        System.runAs(u) 
        { 
            Lead newLead = TestFactory.buildTestLead(String.valueOf(newCampaign.Id),'English');
            insert newLead;

            Lead assertLead = TestFactory.returnLeadById(newLead.Id); 

            // Ensure correct LeadSource as assigned by the AssignsCanadaWebLeadtoQueueOnLanguage trigger
            System.assertEquals(assertLead.LeadSource,Label.CanadianWebLeadSource);

            // Ensure Canadian Web Lead English queue was assigned this Lead by 
            // the AssignsCanadaWebLeadtoQueueOnLanguage trigger
            System.assertEquals(assertLead.OwnerId, newGroup.Id);                                   
        }
        test.StopTest();        
    }

    static testMethod void AssignsCanadaWebLeadtoQueueOnLanguage_French_Test()
    {
        test.StartTest();
        Group newGroup = TestFactory.returnGroupbyName('Canada Web Leads - French');

        Campaign newCampaign = TestFactory.buildTestCampaign('TestCampaign');
        insert newCampaign;

        User u = TestFactory.returnUserByAlias('jaffa'); 

        System.runAs(u) 
        { 
            Lead newLead = TestFactory.buildTestLead(String.valueOf(newCampaign.Id),'French');
            insert newLead;

            System.debug('################# newLead: ' + newLead );
            Lead assertLead = TestFactory.returnLeadById(newLead.Id); 
            System.assertEquals(assertLead.OwnerId, newGroup.Id);
            System.assertEquals(assertLead.LeadSource,Label.CanadianWebLeadSource);            
        }
        test.StopTest();        
    }


    static testMethod void AssignsCanadaWebLeadtoQueueOnLanguage_Negative_Test()
    {
        test.StartTest();
        Group newGroup = TestFactory.returnGroupbyName('Canada Web Leads - English');

        Campaign newCampaign = TestFactory.buildTestCampaign('TestCampaign');
        insert newCampaign;

        User u = TestFactory.returnUserByAlias('gvale'); 

        System.runAs(u) 
        { 
            Lead newLead = TestFactory.buildTestLead(String.valueOf(newCampaign.Id),'English');
            insert newLead;

            System.debug('################# newLead: ' + newLead );
            Lead assertLead = TestFactory.returnLeadById(newLead.Id); 
            System.assertEquals(assertLead.OwnerId, u.Id);
            System.assertNotEquals(assertLead.LeadSource,Label.CanadianWebLeadSource);
        }
        test.StopTest();        
    }    

    static testMethod void AssignsCanadaWebLeadtoQueueOnLanguage_Exception_Test()
    {
        test.StartTest();
        Group newGroup = TestFactory.returnGroupbyName('Canada Web Leads - French');

        Campaign newCampaign = TestFactory.buildTestCampaign('TestCampaign');
        insert newCampaign;

        User u = TestFactory.returnUserByAlias('jaffa'); 

        System.runAs(u) 
        { 
            try
            {
                Lead newLead;                
                insert newLead;
                throw new customException('An exception should have been thrown by the trigger but was not.');
            }
            catch(NullPointerException e)
            {
                //throw new customException('threw exception to trigger');
                Boolean expectedExceptionThrown =  e.getMessage().contains('de-reference a null') ? true : false;
                System.AssertEquals(expectedExceptionThrown, true);          
            }                                       
        }
        test.StopTest();        
    }        
}

Best Answer

To get the catch block to execute, an exception would need to originate from the try block of code in the trigger. If your trigger was doing an update, some validation elsewhere might result in a DMLException being thrown and sometimes you might choose to catch and handle that. But the other source of exceptions is essentially programming errors and the best approach there is to eliminate those errors by improving the logic (and sometimes adding checks for null to avoid the errors).

But if you want to keep the try/catch block and get test coverage on it, you need to figure out some way of setting up the data in your test so that one of the 3 queries fails (e.g. returns no rows).

(That you are using System.runAs suggests that the trigger should be using UserInfo.getUserId() rather than always querying the "jaffa" user.)

Related Topic