Over the Thanksgiving holiday, I had an interesting discussion with some of my Twitter peers about unit testing in WordPress:
— Ryan Duff (@ryancduff) November 29, 2013
If you know me, you know I like unit testing – even when singletons are involved. Test-driven development makes life a whole lot easier for developers and QA teams alike, and I will always be a strong advocate of the practice as a standard in web development. That said, the question of whether or not to test certain parts of an application remains a good one on which there is no definitive answer.
Not To Test
The easiest stance to take is one I often advocate in unit testing overviews or quick tutorials: only test public APIs.
When you’re building an extensible system, testing the API exposed to outside developers is a must. This suite of tests will help you, as the original developer, verify that the API behaves as expected and exposes the functionality your documentation 1 claims it does.
As you further develop your application, you can re-run the tests as often as needed to verify functionality remains intact. This way you aren’t breaking any promises your API design is making to the community.
If a method is declared as protected – or even private – it establishes the method as an internal behaviour and should not be subject to tests. Internal behavior – the inner workings and implementation of your system – should remain a black-box to anyone coding against your API. You can change it as often as you need, so long as the unit tests for your public API continue to pass.
In short – if it’s public, test it. If it’s private, it’s magic and can be treated as such.
The alternative argument, which is one I’m beginning to embrace, is that everything should be tested. Yes, your code exposes an API to the world against which other developers can write code. The functionality of that API can and should be tested as completely as possible.
But unless you’re a solo developer 2, there’s a second API in your codebase. Every application, whether it exposes a public interface for developers or not, contains an internal API. This is the API you code against every day in your project, and it’s just as important as – if not more than – your public API.
Once you invite another developer to work on your project, you’re opening even private and protected methods within your objects to the team. A method for verifying nonces, for example, is something you would not likely ever expose via a public API. However, it contains certain functionality that must exhibit a specific, consistent behavior in order for your application to function properly.
In short – if it’s critical to consistent functionality, even private functionality, test it. There is no such thing as magic.
What is the Question?
There is no generalization I or anyone else can make regarding what code should be tested. The best we can do is offer guidance to help determine which methods should be tested and which should be considered untestable.
Generally, all public functionality – the exposed API – should be tested. There might be pieces of functionality that dictate layout or element positioning; these pieces don’t need unit tests but should instead be covered by integration tests. 3
Generally, private functionality is internal implementation and won’t need to be tested. But if the private functionality is used in a utility context (i.e. it’s used by your code and the code written by the guy in the next cubicle) then it absolutely needs to be tested.
I use the term “generally” above in both circumstances to try to explain a best practice. These are in no ways catch-all rules, however, and your best judgement is required when making the decision whether to or not to test a piece of code. I would always encourage erring on the side of testing. You can never have too many tests.
So let’s say you decide there’s some protected or private functionality in your class that needs testing. How exactly would you go about that? 4
Testing Protected Methods in PHP
If methods are protected, one of the easiest ways to test them is to subclass your object and override them with a public method. This is the approach I use to unit test my PHP singleton pattern, and it works wonders.
Testing Private Methods in PHP
Private methods are a bit trickier. Subclassing won’t provide access since private methods aren’t inherited by child classes. Instead, we can use a neat feature of PHP called reflection. Reflection will allow our objects to look at their own definitions and manipulate the privacy of their member functions, making things accessible to our tests.
There are more things in heaven and earth, Horatio
Unit testing is a huge deal if you want to maintain clean, bug-free, future-proof code. It’s a fantastic way to document your API to ensure functionality behaves as expected farther down the road when client requirements change and new code enters the project. It’s also an effective way to ensure internal consistency between privileged APIs used by your development team.
There is no set of rules that can be universally applied to all code when determining whether or not to test. When you look at a function and ask, “should I test this?” the answer is probably yes, even if it’s not part of your public API.
- You are documenting your API, aren’t you? ↩
- Few developers are truly solo acts anymore. Even if you’re not a member of a larger corporation or entity, I can all but guarantee you will have someone else either contributing to or hacking on your code in the future. ↩
- Integration testing can also be automated, but requires a slightly different toolset than unit testing. It’s a bit beyond the scope of this article, but definitely something you should look into. ↩
- I work in the world of WordPress, and WordPress lives in the universe of PHP. All of the code to follow is PHP, but you can probably abstract the concepts to your language of choice. ↩