By Geoff Escandon (@gjescandon)
Unit Testing is an evergreen subject. On the Force.com platform, 75% of your production Apex code must be covered by tests. This Force.com Developer blog discusses in depth code coverage on the platform to help you hit the mark. However, I am not talking about code coverage today.
Take Out Some Insurance
I am writing this blog to point out that unit testing is not the same as code coverage. We who are building applications in the cloud for our customers and ourselves need business value from unit tests. With good unit tests, we ensure that the mission critical business logic works the way it is supposed to. Confidence and Value. That’s what unit tests mean to you and me.
Unit tests should be confirming that some business logic is working correctly. I recently learned of Behavior-Driven Development (BDD), where acceptance criteria for functionality is defined early. The BDD pattern looks like this:
This type of statement, very similar to an Agile User Story, helps define what we are writing tests for. In fact, this BDD statement fits very well within Force.com testing framework:
//Given [initial context], when [event occurs], then [ensure some outcomes]
….
System.assert(Opportunity.StageName == expectedValue,
‘Expecting Opportunity.StageName = expectedValue when [context] and [event]’);
}
I frequently include the message string ‘Expecting ….’ in the static method System.assert(condition, msg) in order to place a meaningful message about what the test is trying to assert.
Red Light, Green Light
There is another reason that unit tests are critical to us: Failing tests will block the deployment pipeline. On the Force.com platform, you cannot deploy if any tests are failing. To deliver value with agility, we must have a clear deployment pipeline.
Having a daily scheduled job which executes Run All Tests is essential for early warning of failing tests. I use different tools to meet different needs.
- Appirio CMC Metrics can be scheduled to run all tests and report performance metrics over time. Metrics that can be monitored include code coverage, # of failing tests, and long running tests.
- For fast notification of test failures, I leverage Jenkins on Cloudbees.com to receive email alerts. Jenkins essentially is running the Force.com Migration Tool. You can also do just this using any number of tools.
Anti-patterns
There are a number of testing practices which we may convince ourselves to do, but in reality are not actually valuable. Here are a few:
- Assigning test writing to offshore or noobs? DIY! When you throw test writing over the wall, the test developers will not be intimate with your code style, nor the requirements and constraints that led to your final product. What’s more, you will not learn to write testable code without writing your own tests. For good tests of good code, do it yourself.
- Requiring 100% Code Coverage? Just say no. If you are truly writing unit tests to validate your business logic, it is probably not necessary to hit 100% coverage everywhere. (However, if you are writing good testable code, it should be very easy to reach >90% Code Coverage.)
- Manual Testing? Keep it DRY! Don’t Repeat Yourself. When you see yourself or the QA team repeating the same regression test over and over again, you should seize the opportunity to automate the test. This typically involves generating adequate test data to setup the correct initial state.
Code that works
At the end of the day, we are working in the cloud to deliver value more quickly. Unit tests that ensure valid business logic and alert for any blockages in the deployment pipeline are delivering true value. The minimum requirement of code coverage enforced by your team or platform should be very easy to maintain when your great code is complemented with meaningful unit tests that are scheduled to run daily.
Further reading:
Testing like the TSA
How deep are your unit tests