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
finalistfinalist 

Unit Tests for addError() described well, ineffective

I've run into an odd scenario involving a cross-object validation that I'd like some fresh eyes on.  I want to prevent a Case from being created, updated or closed if the Case.Type is not in agreement with the associated Account's recordtype.

 

It sounds like a straightforward use case for a Validation Rule, but insert()s slip on through anyway (perhaps because Account.recordtypeId isn't available until after the Case is first saved..?  Guessing here.)  Updates and Case close are prevented, but that's not enough.

 

So I created a Case trigger (before insert, before update) that checks for Case.Type, creates a Set<Id> of Account Ids for the types I want to validate, retrieves the Account.Ids for the Account recordtypes I care about, and then uses addError() to flag those Cases that violate the rule.

 

i.e. Accounts of recordType 'X' must have Cases of Case.Type "Xtype", or I apply addError('Please use Case type "Xtype" when blah, blah blah');

 

The trigger works great, but is proving difficult to test:

 

#askForce pointed to a great example of Unit Testing for (presumably) an addError() use Testing Example

 

I create a Case with an invalid type, then attempt an insert() or update() using a try/catch block, then use the example to look at the exception - but no exception is thrown.

 

UI works great, though.

if (c.AccountId == a.Id && c.Type <> 'Xtype') {
	c.addError(' You must select a Case type of \'Critical Care\', as this is a Critical Care account.');
}

 

Marty Y. ChangMarty Y. Chang

Hello, finalist,

 

How are your validation rules setup?  I think validation rules should be enforced regardless of whether you perform a DML operation through the UI or through Apex.

 

Regarding the addError method, it does not cause an exception to be thrown.  You are actually gracefully handling the error instead of throwing an exception.  You can validate your code by looking for the error in the Database.SaveResult objects returned by the Database.insert method, as demonstrated in the example at the bottom of the article, "Insert Operation" from the Force.com Apex Developer's Guide.

finalistfinalist

I am working from a trigger, as the Validation Rule doesn't prevent a record from being inserted (my suspicion being that the related Account.RecordTypeId is not visible until after the record is saved).  

 

Using addError() in the trigger does prevent both an insert or an update from the UI, and yet in the Unit Test, with the same data that fails (as intended) from the UI, results in the database.saveResult returning .IsSuccess() (true) from the Unit Test.

cs = new Case(// Account.recordtype=target RT, Case.Type=undesirable);
        
// Insert should fail, as Case.Type does not match Account recordtype 
try {
        System.debug('===== about to attempt a database.insert()...');
        database.saveresult sr = database.insert(cs);
	if(!sr.isSuccess()) {
	    System.debug('===== NOT sr.isSuccess()');
 	    Database.Error e = sr.getErrors()[0];
  	System.assert(!e.getMessage().contains(' You must select a Case type of \'<value>\', as this is a <recordtype name> account.'),
	        		e.getMessage());
}
else {
      System.debug('===== sr.isSuccess() after all');
}

// In the debug log, this 2nd message ^ indicating a successful insert is recorded.

 

 

 

Andrew WilkinsonAndrew Wilkinson

Here is an example fro my blog to test the addError method. Hope it helps...

 

Unit Test for Add Error