+ Start a Discussion
jstellingjstelling 

Better way to create TEST data around Validation Rules??

I have built a trigger on an object that updates fields on a related object.  This related object has many validation rules in place that are causing issues in building test data in my test class for this trigger.  My current approach is to create the needed test data in the correct manner to allow the validation rules to pass.  However, this means that if these rules change in the future, the test class might likewise also need to be updated.  In an effort to produce development that is low-maintainence in nature, flexible, and adaptable to changes, I would prefer to not use this approach.

 

Does anyone have any best practices or guidance on ways to write APEX tests that would remove the dependence on the validation rules?  The way I see it, the validation rules shouldn't cause my APEX tests to fail, as they would not indicate any defects in the APEX code itself, but the test data being generated.  Therefore, should we exclude these rules and leave the testing of them to System or Functional User testing?

 

The only solution I have come up with so far is to create a hidden "isTest" checkbox on the object with the validation rules.  This check box would be used in the rules to exclude records having this flag True.  This flag would only get set by my test class, and therefor circumvent the rules.  I'm sure there is some flaw in this approach that I am not thinking of, but am not sure.

 

 

Best Answer chosen by Admin (Salesforce Developers) 
Ritesh AswaneyRitesh Aswaney

There are two ways to look at this - true that validation errors causing tests to fail indicate no failure on part of the apex code - but the apex code in your class is partly at fault - as its trying to create test data which does not conform to system rules.

another drawback of using isTest would be that you wouldn't know until very late in the day that new validation rules are breaking your tests - and learning about stuff like that when you're deploying to production can be very ... frustrating to say the least !

 

i'd recommend you create a Test Class Helper class which creates all possible objects you have in your schema, rather than scattering create's all over your code. in this way, you can minimise the impact of a validation rule change to just one class rather than in each class trying to create an account say.

 

My two pence - if you'd like a really nice to have, you could possible set up custom settings to hold fields you want to populate for each object, and then create sobjects dynamically for your test, 

using sObject.put(Custom_Setting__c.get(FieldName), CustomSetting.get(FieldName).value)

 

In this way, all you'd need to configure when you add a new validation rule is prolly another row to the custom setting, and it will autoset those values for test data creation.

All Answers

Ritesh AswaneyRitesh Aswaney

There are two ways to look at this - true that validation errors causing tests to fail indicate no failure on part of the apex code - but the apex code in your class is partly at fault - as its trying to create test data which does not conform to system rules.

another drawback of using isTest would be that you wouldn't know until very late in the day that new validation rules are breaking your tests - and learning about stuff like that when you're deploying to production can be very ... frustrating to say the least !

 

i'd recommend you create a Test Class Helper class which creates all possible objects you have in your schema, rather than scattering create's all over your code. in this way, you can minimise the impact of a validation rule change to just one class rather than in each class trying to create an account say.

 

My two pence - if you'd like a really nice to have, you could possible set up custom settings to hold fields you want to populate for each object, and then create sobjects dynamically for your test, 

using sObject.put(Custom_Setting__c.get(FieldName), CustomSetting.get(FieldName).value)

 

In this way, all you'd need to configure when you add a new validation rule is prolly another row to the custom setting, and it will autoset those values for test data creation.

This was selected as the best answer
jstellingjstelling

Thank you for the tips.  Are you talking about creating a Utility class/methods for generating test data?  This does mean that the utility class counts towards our APEX code limits as it must be public, which is not allowed for @isTest classes?  I still like the idea of this utility class though, even inspite of this drawback.

 

Good suggestion on the use of custom settings to make the entire code dynamic.  I've been considering this for another project I am working on and think it will work well.

 

thanks again!

 

Doze2KatzsDoze2Katzs
I used to think along the lines of trying to bypass validation rules, but then realized if you are bypassing the rules then you are in essence creating data that doesn't reflect real data in your organization. So, I then learned how to write better test coverage. I use some standard code that creates certain records such as Accounts, Contacts, Opportunities. Then, I usually have to create other records from custom objects. I believe it is better to not bypass the validation rules because you implemented them for a reason and if your validation rules change, so should your test coverage. All of my custom classes/controllers have at least 90% code coverage and we have many validation rules on our objects. That's my .02!
jstellingjstelling

Thanks for the input.  I will continue coding with the rules in mind, and just structure the test classes to make the maintenance of them easier, using a Test Data Utility class as suggested by Ritesh.

 

 

Doze2KatzsDoze2Katzs
Along the approach of a utility class, I created one that creates certain records I use frequently throughout my test coverage. So, if changes are made, I only have to change them in one spot. Some of them are: static User temp_User = [select id, Name from User where Name = 'John Doe']; static RecordType temp_RecordType_PI = [select id, Name from RecordType where Name = 'PI']; static Account a1 = new account(name='Test Account'); A bunch more are in there, but just gave you a few. I then use them in my test coverage as needed.
Roger WickiRoger Wicki
@Doze2Katzs:
Let me quote a sentence of yours:
I used to think along the lines of trying to bypass validation rules, but then realized if you are bypassing the rules then you are in essence creating data that doesn't reflect real data in your organization.
 
Sometimes exactly that is the opposite. We have migrated our database to Salesforce after having an almost text-field-based environment for 10 years. There were no validation rules on correct data entry. We corrected most of it during migration, but there are left-overs. Ever since, I am in charge of continuously updating, improving and automating things in our org. Every other day I stumble over non-standard records. So bad data is real.
Whenever somebody just as much as makes a field required on a page layout, it means that every existing record which does not have that field set to be invalid. This is a point which I'd like my handler classes to consider so they don't fail in a generic Salesforce error message. If I am lucky and a user reads an error message, I want them to understand what may be the problem. So I build exception handlers in my code which displays error messages accordingly.

Because writing such exception handling uses quite some lines of code sometimes, I need also the exceptions to be tested in test classes. But I can't create sample bad data because the validation rules fire. I have to find a way around it.


Also @Doze2Katzs:
I use Creator classes for my most used objects like User, Account, Contact and Opportunity. The standard "constructor" if you want to call it that way just fills the required fields. If dependant fields need to be set (e.g. dependant picklists, dependant due to validation, etc.) I set a flag on the static variable for the creator class accordingly and if I want every single field to be filled with sample data, I set another one.
Whenever a test class needs to create accounts for example, the accounts are created with the creator class. Like that I can be sure, that they pass latest validations. I just had to exclude any Account with '%Test%' from my duplicates rule ;)
My creator classes all come with static methods (to set static variables) like setting the owner, record type or any field that may need to be set to a specific value in order to be tested with.
Vinay TVinay T
User-added image
Can anybody anser this please ?
Preparing for Developer  certication exam
Eric-∑Eric-∑
@Vinay T, I think the answer to your question is A.

To bypass validtion rules in test method or apex classses. What we did before is create a checkbox field like BypassValidationRule__c and inclue this checkbox in all your validation rules. For example, if your current validation rule is OR(A, B), then new validation rule could be AND(NOT(BypassValidationRule__c), OR(A, B))

Then when you insert/update the record, you can set BypassValidationRule__c to True to bypass the validation rules. You will need to create a workflow rule to set BypassValidationRule__c back to False, so that the validation rules still enfore for user's action. The validation rules happen before the workflow fires, so it will work. 
 
Roger WickiRoger Wicki
@Eric-∑
That's actually a very smart idea. On what object did you have this? I think it should be as global as possible, but still selectable in formulas / validation rules. (Custom) Permissions or Custom Settings would come to my mind. These are accessible via validation rule and editable via apex.