function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
RupBRupB 

How do I test for an exception('addError') in a Trigger ?

Hi,

 

- Sorry to bother, but I found no answer to this wuestion either on the web, or in the dev forum, or in the Apex documentation - 

 

I have a trigger, which detects error conditions and feeds errors to the class or field.

This gives a nice result interactively, in the GUI.

But how do I write test code to catch these errors ?  Is there a System.AssertException(), or the equivalent ? 

 

trigger createOrder on Asset (after insert, after update) {[...] if (price.get(a.Product2Id) == NULL) { System.debug(' error : no active price'); a.Product2Id.addError('no active price on the Product'); }[...]}

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
sfdccoder1sfdccoder1

Hi RupB,

 

I worked out a solution for a similar case I had where addError() was used for a record and not for a field.

I  believe though it should work for your case too.

 

The idea is to:

 

a. Write code in the test class that will cause the trigger to 'addError()'.

b. Surround the above test class code with try - catch.

cAssert that an exception is thrown and that the exception message is the same one you created with 'addError()'.

 

Here's an example (partly pseudo) code from both trigger and test class:

 

Trigger: 

 

if(myRecord.MyField == some value)

myRecord.addError('My Error Message');

 

 

Test Class: 

 

try

{

MyRecord.MyField = a value that will cause an error

update MyRocord;

throw new MyException('An exception should have been thrown by the trigger but was not.'); // 1. If we get to this line it means an error was not added and the test class should throw an exception here. 2MyException class extends Exception.

}

catch(Exception e)

{

Boolean expectedExceptionThrown =  e.getMessage().contains('My Error Message')) ? true : false;

System.AssertEquals(expectedExceptionThrown, true);

 

 

Let me know if this did the work

 

 

Message Edited by sfdccoder1 on 09-01-2009 01:32 AM

All Answers

sfdccoder1sfdccoder1

Hi RupB,

 

I worked out a solution for a similar case I had where addError() was used for a record and not for a field.

I  believe though it should work for your case too.

 

The idea is to:

 

a. Write code in the test class that will cause the trigger to 'addError()'.

b. Surround the above test class code with try - catch.

cAssert that an exception is thrown and that the exception message is the same one you created with 'addError()'.

 

Here's an example (partly pseudo) code from both trigger and test class:

 

Trigger: 

 

if(myRecord.MyField == some value)

myRecord.addError('My Error Message');

 

 

Test Class: 

 

try

{

MyRecord.MyField = a value that will cause an error

update MyRocord;

throw new MyException('An exception should have been thrown by the trigger but was not.'); // 1. If we get to this line it means an error was not added and the test class should throw an exception here. 2MyException class extends Exception.

}

catch(Exception e)

{

Boolean expectedExceptionThrown =  e.getMessage().contains('My Error Message')) ? true : false;

System.AssertEquals(expectedExceptionThrown, true);

 

 

Let me know if this did the work

 

 

Message Edited by sfdccoder1 on 09-01-2009 01:32 AM
This was selected as the best answer
RupBRupB

Sounds great, I will give it a try.

 

Rup 

RupBRupB

Hi sfdccoder1, thanks for the tip which works well.

 

Here is some more precise error detection code, especially for errors on fields ; in my case, I am detecting an error on the Product2Id field of an Asset :

catch(Exception e) {

System.Assert(e.getMessage().contains('FIELD_CUSTOM_VALIDATION_EXCEPTION'));

System.Assert(e.getMessage().contains('Product2Id'));

System.Assert(e.getMessage().contains('My Error Message'));

}

 

I hope this helps.

Cheers,

Rup 

 

Message Edited by RupB on 01-09-2009 10:57 AM
vinothvinoth

Hi I need to write test class for the following trigger, but i could able to cover 65%.

 


trigger FormTypeAttachments on Attachment (before insert) {

List<Information_document_scan__c> FormType = [select id, Select_Form_Type__c from Information_document_scan__c where id =:Trigger.New[0].ParentId];
 List<Attachment> atts = Trigger.new;
 for(Attachment a:atts) {
    if(FormType[0].Select_Form_Type__c=='Signature Card'){
        a.addError('Signature Card should have only Four attachments.To go back to record,Click "Done" Button');
    }
  }
}

"a.addError" is not covering, how to Achieve more then 75%?

Ivan GrgurinaIvan Grgurina
Hi vinoth,
trigger doesn't have to have more than 75% coverage, that rule just applies to regular Apex classes.
Kris SparksKris Sparks

sfdccoder1 Thanks for the help. This works great. I combined your answer with the specifics from RupB and checked my custom message, though I didn't throw an exception in the try block: 

try {
        center.Name = 'Update Center Name';
        update center;
      } catch(Exception error) {
        System.assert(error.getMessage().contains('Update failed.'));
        System.assert(error.getMessage().contains('FIELD_CUSTOM_VALIDATION_EXCEPTION'));
        System.assert(error.getMessage().contains('You do not have permission to '
                                                  + 'change the name of a center. '
                                                  + 'Please contact IT for assistance.')
                                                );
}
Kris SparksKris Sparks
sfdccoder1 Thanks for the help. This works great. I combined your answer with the specifics from RupB and checked my custom message.

Note: I didn't understand at first why the exception in the try block is neccesary, but it is. When I excluded it the record could update successfully and the test would "pass". The exceptions throws an error if the record updates successfully, which in my test case it should not:
private class TestAfterCenterTrigger {
  private class CenterNameUpdateException extends Exception {}

​.
.
.

try {
        center.Name = 'Update Center Name';
        update center;
        throw new CenterNameUpdateException('afterCenter.trigger should have run .addError '
                                          + 'on center.Name and invalidate the update. '
                                          + 'test must be runAs user not in authorizedProfiles');
      } catch(Exception error) {
        System.Assert(error.getMessage().contains('Update failed.'));
        System.Assert(error.getMessage().contains('FIELD_CUSTOM_VALIDATION_EXCEPTION'));
        System.Assert(error.getMessage().contains('You do not have permission to '
                                                  + 'change the name of a center. '
                                                  + 'Please contact IT for assistance.')
                                                );  
}

 
salesforce snehalksalesforce snehalk
Thanks @sfdccoder1. Your answer perfectly works for me. Just the thing is, I didn't use Custom Exception, just handled exception in catch block and checked it with the exception I am throwing from my Trigger. It worked. Thanks again..
Simon WilkinsonSimon Wilkinson
Hi, just an addendum to this.

I'd always suggest that it is better for a test to fail off the back of an assertion than an exception (I accept that in the background these things are probably defined in the same way).

In this case I would replace the new exception that is raised with an assertion that should fail if the DML operation (in this case) succeded when it shouldn't have.

Using the previous example (I've assumed this is a custom object named Center__c):
...
  try {
        center.Name = 'Update Center Name';
        update center;
        Center__c center_refreshed = [SELECT Id, Name FROM Center__c WHERE Id = :center.Id];
        System.AssertEquals('Update Center Name', center_refreshed.Name);
      } catch(Exception error) {
        ...
  }
...