Testing is a well-established concept in all software development platforms, and Salesforce is no different. Every Salesforce developer knows the target of 75% code coverage for every Apex class they write. But many are less sure of the underlying reasons why tests are important, the benefits of good tests, and how easy it is to fall into the trap of writing bad tests.
In this article we'll discuss why tests are important, their benefits, and how testing fits into a modern DevOps process.
Safely managing change is critical
Salesforce is a business critical platform. From sales to marketing to support, entire sections of companies rely Salesforce operating successfully for them to function.
The impact of making a breaking change can be severe, and to compound the issue there is no native support for rollback if you introduce a problem. As a result, it's critical that any changes made to orgs are stable and function as expected.
Tests gives Salesforce teams the confidence that changes function as expected and are safe to release.
Why should developers test?
Aside from mitigating the risk of an impact on business as usual, there are a number of reasons why Salesforce developers should want to test their code before it gets released:
Tests protect their development investment against erroneous changes later down the line
Tests prove that the features accurately represent business requirements, and give confidence that the developers are spending their time building the correct things
Tests help teams deal with platform upgrades in the fast-moving world of Salesforce releases
Benefits of good tests
Good tests have a range of benefits:
They catch problems early, while they're easy to fix
They prove code works, and provide evidence of progress for teams
They keep development teams honest on code quality and progress; stopping to write tests often makes developers think about their approaches and can highlight shortcuts or other technical debt that they should be aware of
They reduce risk by acting as an additional code review process before features are released
They can be easily re-run in the future, either as part of testing further down the release pipeline, or in the future as part of additional development work
Problems with bad tests
Not all tests are equal! Good tests are extremely valuable to development teams. Bad tests, however, can actually hurt progress and even be worse than no tests at all.
Are a maintenance headache. They may easily break and require constant fixing. If they're badly written, they may also be hard for other developers to understand and debug when they go wrong.
Can provide a false sense of security without actually protecting or testing what developers care about. This can lead to disasters down the line.
May not be testing the correct behaviour, so don't actually verify that the business user's needs are being met. This can lead to a degradation in the relationship with the team's end users.
Can stagnate and become deployment blockers further down the line. Silent test failures are the bane of many a release team on a tight schedule.
6 practical ways to improve tests
Writing tests that get you to the magic 75% code coverage requirement is easy, but writing great tests that help protect you as you work is a real skill.
Luckily there are some common ways which can be used to help ensure teams are creating good tests.
Isolation: run tests with seeAllData=false
Good unit tests interact with the smallest amount of code possible. Isolating tests ensures they're only interacting with data that’s relevant to that specific test.
By explicitly setting
false, developers can ensure their tests won’t be affected by data changing within their org. This has only recently become the default for Salesforce tests, but it’s still good practice to call it out so anyone else reading your test will know the constraints applied.
Arrange - Act - Assert
This is good practice for unit tests on all platforms, but is even more important in Salesforce. Start by arranging anything needed for the test. This can involve preparing test data. It's often a good idea to pull this into a separate method, as it helps keep your test compact and easy to read. Next, act, executing the business rules or logic against the things that have been arranged. Finally, all good tests should assert their results to check the outcome. A test that does not assert the result is not a test at all.
Run tests as real user profiles
By default, Salesforce tests run at a system level and have visibility into all org properties and configurations. Make sure some tests run using real user profiles, to check that the test is successful when constrained by their permissions.
Use Test.startTest() and Test.stopTest()
If there are a large number of tests, running them can be quite compute intensive. Salesforce enforces certain governor limits on user activity to limit performance degradation. Using
Test.startTest()gives developers a new set of governor limits for the act stage of their test.
Test.stopTest() then allows them to return to their previous governor limits. It also causes any asynchronous code queued up during the act stage to execute before the assert stage. For example, it allows developers to test
@future methods to check they are working as expected.
Exercise bulk trigger functionality
Aim to have at least one test per trigger that calls more than one object - ideally around 10-20 objects. This is not to test the limits of how many objects can be called, but to test that calling the trigger with multiple objects works. Don’t add too many objects, as Sandboxes tend to have limited performance and can end up timing out, causing tests to fail (even if that same trigger would run perfectly on your Production instance).
Automate test execution
Once great unit tests are in place, it’s important to run them on a regular basis. Beyond providing an ongoing awareness of the health of your orgs, regular testing allows developers to find and fix silent test failures before they become deployment blockers.
Want to learn more?
Watch our presentation at Dreamforce 2016 on testing best practices:
We also released a webinar on testing: