Here are some best practices that I felt need to be followed while writing test classes in Salesforce , Do add your thoughts too
- All test methods should reside in a separate class from the class in which the method being tested resides.
- These classes should be appended with the word Test followed by the name of the class being tested, e.g. OpportunityServicesTest.
- These classes should all use the @isTest annotation.
- Each method in the production class should have, at a minimum, one corresponding test method in its test class and should be appended by “test”
- There should be a minimum of “Null Pointer Exception test” as part of negative testing for each method, specially the methods that accept parameters.
- A method without an assert statement is not considered a test method. Large number of relevant assert statements increases confidence in the correct behaviour of business logic.
- There should be a comment with each assert statement explaining what is being tested and what the expected output is
- Only use isTest(SeeAllData = true) on class methods in exceptional cases where there are sObjects that doesn't allow DML operation e.g. PriceBook creation
- No hard coded ids of any sObject in any test method.
- If a Constant needs to be asserted ,its a best practice to reference that from the Constant class or from Custom Labels or Custom Settings. Using hard coded string in unit tests( or any class for that matter) will trigger failures when things like Picklist values change
- All test data creation should be done from a Utility class. This allows for a streamlined creation of test objects that adhere to all the validation rules.
- Any business logic that needs to be tested should be enveloped within a Test.runAs(user) statement so profile restrictions can be tested. . Using any admin profiles should be avoided.
- All private methods should also have its corresponding unit test method. In the production code, add a public method for each private method and prepend it by “exposeForUnitTest_”.
- Creating multiple test method for testing that same production code method should be avoided. We want to ensure that our unit test methods are properly testing the logic but the same time the efficiency of the unit test method should not be ignored. All the unit test methods run with every deployment so the cumulative run time should be as small as possible
- Any asynchronous method testing should include Test.startTest and Test.stopTest. Test.stopTest forces the asynchronous methods to run so the results could be asserted.
- Any exceptions that are caught in the production methods should be tested by feeding the test data that throws exception. Exception Type and error message should be asserted.
- Every class should have test coverage close to 95% as possible. The focus should be on asserting method behaviour rather than increasing coverage. There are very few instances where a method behaviour is not straightforward to reproduce and hence test. These should be properly commented.
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_system.htm (test assertions and debug/logging)