Salesforce Test Class best practices

If you are a developer and ever written Salesforce Apex classes/Triggers – you know that you have to write the corresponding Test methods so that Salesforce allows deploying them in higher environments. As per Salesforce, each of the Apex class must have a minimum of 75% code coverage and at-least 1 line is covered in each Trigger. Code coverage is calculated by dividing the number of unique Apex code lines executed during your test method execution by the total number of Apex code lines in all of your trigger and classes. This does not mean that we should only aim for minimum but always try to achieve 100% code coverage. I know writing test classes seems to be a pain as I felt the same when I started my journey but then once you are used to it – becomes easier and fun.

I have jotted down below points which needs to incorporated accordingly while writing test methods/classes :

  1. All test methods should be put in a separate class from the actual class where the method to be tested resides.
  2. Name your test classes either – TestClassName or ClassNameTest, where ClassName is the Apex class name. This way it is easier to identify for which actual class this was written for.
  3. All test classes should be annotated using keyword ‘@isTest‘. This way Salesforce ignores the code/lines from these test classes while calculating overall code coverage for the organization.
  4. Each method in the actual class should have a minimum of corresponding test method in the test class. There could be more than 1 test method for each actual method to cover for multiple scenarios.
  5. Each test method should follow the signature – ‘@isTest static void myTest()‘ or ‘static testMethod void myTest()‘.
  6. Use of multiple assert statements in each test method is encouraged as it increases the confidence in the logic being tested. Further adding comments with each assert statement makes the test methods more readable and understandable.
  7. Avoid using any hard-coding of sObject Id’s or referencing any hard coding Strings. Use Custom Labels or Constants class values so that if a change is needed in future, it needs to be done only at one location.
  8. Private member variables and methods in actual class should be annotated with ‘@TestVisible‘ so that test methods can access them.
  9. Use of ‘@isTest(SeeAllData=true)‘ annotation should be avoided as it opens access to unnecessary organization data which varies from org to other such as Custom Setting and will cause inconsistency. Instead one should created such org specific data as needed as per next point.
  10. Test data creation should be done in a separate Utility class or in a test method annotated as ‘@testSetup‘.
  11. The business logic to be tested should be enclosed within System.runAs(User), where User has the same profile and settings with whom you want to run these test. This way Profile settings, FLS and any other restrictions can be tested as well.
  12. Test.startTest/Test.stopTest should be used in your test method as it marks the point in your test code when your test actually begins and stops respectively. A fresh set of governor limits is provided for the logic between Test.startTest/Test.stopTest to test it accurately as some limits might have been used in setting up test data.
  13. For Asynchronous method testing, Test.startTest/Test.stopTest should definitely be used as Test.stopTest forces the asynchronous method to run and complete, so that results can be asserted after the completion.
  14. Test for positive, negative, null-pointer and bulkified scenarios to have more confidence in the testing.
  15. Any exceptions being thrown in actual class must also be tested by feeding appropriate test data to throw/generate exception. This also helps in achieving more code coverage and overall increase of coverage.
  16. Every Actual class should be tried to reach to a code coverage level of 100%. If not possible, provide enough comments in test class for better maintenance in future.

Feel Free to provide your valuable comments or point out any issues or scope of improvement in this post.