+ Start a Discussion
TehNrdTehNrd 

Try-Catch Code Coverage question

Our triggers add great new functionality but as of now none are system critial. So for each trigger I have try/catch statements that catch standard exceptions and adds it to a custom built exception log I've created. http://community.salesforce.com/sforce/board/message?board.id=apex&message.id=978\

The problem I've run into is covering the catch code with test coverage.  It seems like a Catch 22. If my test throws an exception it fails, but I somehow need it to throw an exception to cover the catch statement. Even with the catch code not covered we still have 90% code coverage but I'd like to cover as much as possible.

-Thanks
Jason
knicholsknichols
Great post, I was wondering the same thing...
mikecaimikecai
Has this been resolved?
TehNrdTehNrd
I have still not figured out a good way to cover catch code.
ascuccimarraascuccimarra
Will there ever be a solution for this? It's incredible that if you use a try-catch policy to handle errors reaching an acceptable code coverage is so difficult Just because you can't cover the catch statement.
TehNrdTehNrd
This is the only way I have figured out to cover try-catch code. It is not the prettiest but it gets the job done.

try{ //some code //Exception Testing and Handling--------------------------------- if(utility.throwExceptionError() == true){ string e = null; e.tolowercase(); } }catch(Exception e){ //Catch code }

 


In a utility class I have a static boolean that I set to true when testing so that a null pointer exception error occurs and then I can test the catch block of code.
guest1231231guest1231231

Using this testing example as a template worked for me and covered my try catch code block.

 

Testing Example

 

 

static testMethod void runNegativeTestCases() {

       User u3 = [select id from User where alias='tuser'];
       System.RunAs(u3){
        
       System.debug('Inserting a record with 501 miles... (negative test case)');
        
       Mileage__c testMiles3 = new Mileage__c( Miles__c = 501, Date__c = System.today() );
        
        try {
            insert testMiles3;
        } catch (DmlException e) {
            //Assert Error Message  
    
            System.assert( e.getMessage().contains('Insert failed. First exception on ' +
                'row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, ' +
                'Mileage request exceeds daily limit(500): [Miles__c]'), 
                e.getMessage() );
                  
            //Assert field  
    
            System.assertEquals(Mileage__c.Miles__c, e.getDmlFields(0)[0]);
            
            //Assert Status Code  
    
            System.assertEquals('FIELD_CUSTOM_VALIDATION_EXCEPTION' , 
                                 e.getDmlStatusCode(0) );
        } //catch  
    
       } //RunAs(u3)   
    
    } // runNegativeTestCases()   

 

 

 

JPlayEHRJPlayEHR

I've been using this method to cover the try-catch statemtents in our test coverage, but now we run into the problem that custom validation rules on related objects aren't firing when the trigger inserts them (i.e. firing a trigger to create a related [custom_object__c] record every time an Account checkbox is checked on insert).  

 

For a weird example, say you want to allow users to create Accounts and also create records of a custom object (related to the Account) called "Non_Swear_Word__c".  

 

You allow swear words to be entered into a text field on the account, but you won't allow swear words to be entered into the corresponding field on the Non_Swear_Word__c object.  

 

You create a validation rule on the Non_Swear_Word__c object to keep the user from entering any of the swear words that come to mind (these will flow easily once you arrive at paradox of what we're trying to accomplish).  

 

Next you create a trigger on the account that automatically creates a Non_Swear_Word__c record once an account is inserted with a checkbox checked.  The trigger would transfer this "Dev_Thoughts" textfield value over from the account to the Dev_Thoughts__c field on the new Non_Swear_Word__c record.  If the value of Dev_Thoughts__c is one of the swear words in your validation rule, it's going to throw an ugly validation error if there's no try-catch.  If there is a try-catch that merely asserts and debugs, it will allow the box to be checked on the account, but will error in the background (you won't see an error) and the trigger WILL NOT create a Non_Swear_Word__c record like it's supposed to when the box has been checked.  You may not even notice that it didn't create it. This is a problem.  Here's an example of what I'm talking about (the checkbox field will be called "Not_using_swears__c"):

 

trigger AccountTrigger on Account(after insert){

	LIST<Non_Swear_Word__c> newNSWs = new LIST<Non_Swear_Word__c>();

	for(Account acct trigger.new){
		if(acct.Not_using_swears__c) 
		newNSWs.add(new Non_Swear_Word__c(
			 Name=acct.name, Dev_Thoughts__c=acct.Dev_Thoughts__c));
	}
	insert newNSWs;
}

 If there's a swear word in the Dev_Thoughts__c field, this will blow up with a huge red error on the Account edit page and will not let you save it until you remove the swear.  It works, but it's ugly and hard to read.  Also, it will send the developer an email every time somebody hits that unhandled exception error.

 

 

trigger AccountTrigger on Account(after insert){

	LIST<Non_Swear_Word__c> newNSWs = new LIST<Non_Swear_Word__c>();

	for(Account acct trigger.new){
		if(acct.Not_using_swears__c) 
		newNSWs.add(new Non_Swear_Word__c(
			 Name=acct.name, Dev_Thoughts__c=acct.Dev_Thoughts__c));
	}
	try{ 	
		insert newNSWs;
		boolean test=true;
		if(test){
			test=false;
			string e;
			e.toLowerCase();
		}
	}	
	catch(Exception Ex){
		system.debug(Ex);
	}	
}

 

 

This will prevent an email from going to the developer and it will allow the Account record to be inserted, and will be 100% covered in the test coverage (not shown), but it WILL NOT create the related Non_Swear_Word__c record.  

 

This is the paradox.  You'll have to either put a validation rule on the account that prevents the user from entering swears when they've checked the "Not using swears" checkbox (in this case the most logical).  Option 2 would be to force the error onto the screen like this:

 

 

trigger AccountTrigger on Account(after insert){

	LIST<Non_Swear_Word__c> newNSWs = new LIST<Non_Swear_Word__c>();

	for(Account acct trigger.new){
		if(acct.Not_using_swears__c) 
		newNSWs.add(new Non_Swear_Word__c(
			 Name=acct.name, Dev_Thoughts__c=acct.Dev_Thoughts__c));
	}
	try{ 	
		insert newNSWs;
		boolean test=true;
		if(test){
			test=false;
			string e;
			e.toLowerCase();
		}
	}	
	catch(Exception Ex){
		system.debug(Ex); //leaving it just for fun
		for(Account acct: trigger.new)
			acct.addError(Ex.getMessage());
	}	
}

 While this would be 100% coverable under test coverage (not shown), it will also throw an error message every time the user tried to insert an Account.  This can be prevented by removing:

 

 

boolean test=true;
if(test){
   test=false;
   string e;
   e.toLowerCase();
}

 What this means is that you'll have 1 line of code not coverable by test coverage.  

 

 

If you REALLY want to cover this line of code, you'll have to create a compromise workaround to allow most of all 3 to happen.  The following will allow the Account record to be inserted and allow the Non_Swear_Word__c record to be inserted by editing the offensively vulgar language in the Dev_Thoughts__c field before inserting the Non_Swear_Word__c record:

 

trigger AccountTrigger on Account(after insert){

	LIST<Non_Swear_Word__c> newNSWs = new LIST<Non_Swear_Word__c>();

	for(Account acct trigger.new){
		if(acct.Not_using_swears__c){ 
			//Check for swears first
			string properString = acct.Dev_Thoughts__c;
			if(properString!=null&&properString.toLowerCase().contains('$#!7'){
				properString = 'EDIT FOR EXPLICIT CONTENT';
			}
			newNSWs.add(new Non_Swear_Word__c(
			Name=acct.name, Dev_Thoughts__c=properString));
		}
	}
	try{ 	
		insert newNSWs;
		boolean test=true;
		if(test){
			test=false;
			string e;
			e.toLowerCase();
		}
	}	
	catch(Exception Ex){
		system.debug(Ex); //leaving it just for fun		
	}	
}

 

 

Only problem is that you'll have to make sure that any and all validation rules on the Non_Swear_Word__c object are handled in your Account trigger...otherwise the new Non_Swear_Word__c record won't be created from the Account Trigger.

 

 

 

JPlayEHRJPlayEHR

I just had a new discovery (for myself at least).  if you put your try-catch all on the same line then it appears that it doesn't need to error out in order to cover that catch...it covers the line with the "try" part. For example:

 

 

try{insert newRecord;}catch(Exception e){system.debug(e);} 

 

 

BenPBenP

I found that you can retain the structure, but just don't have the catch on a new line.

 

try{
code;
code;
code; }catch (System.QueryException qe){}

 

Rhoose-boyRhoose-boy

Excellent - that worked for me.

Kelly KKelly K
Still works in 2014.
Anand Jeevakan 5Anand Jeevakan 5
Yea, still works. Simple || Best.
Seyitbek Usmanov 14Seyitbek Usmanov 14
Still works in 2018!!! Thanks guy for the advice. These forums are the best.
JPSeaburyJPSeabury
I hate that BenP's solution is the best, but have to agree with Anand, simplest is best! Although that code formatting is KILLING my OCD!!
Oce Admin 20Oce Admin 20
Still works during the Covid-19 Apocalypse!!! These forums rocks!