As a follow-up to my last post about PHP unit testing, I recently gave a talk at WordCamp Boston about how to write testable WordPress plugins. You can see the talk slides here:
You can also watch the talk here, although the audio quality isn’t great.
The premise of my talk was mainly that having testable code is a really great idea, even (and perhaps this is surprising) if there are no actual tests. Of course, without writing tests it’s hard to know for sure, but some experience will go a long way for future projects.
Even though this was at a WordCamp, my talk is not really WordPress specific. It really applies to any unit testing in PHP. In it, I gave an analogy to help my audience understand some of the concepts. Here’s that analogy:
Why have tests?
If you asked a friend to make you Pad Thai, you’ll probably get something edible, but maybe your friend isn’t such a good cook. If you don’t like the food, how can you tell what went wrong?
Defining your dependencies is important. “I want Pad Thai” vs. “I want Pad Thai, made with the following ingredients” will help. Even better, “I want Pad Thai, made with the following ingredients, ordered from this store, using this recipe”.
Mocks (AKA Stubs)
Using mocks is like asking the store to only sell your friend a particular brand of noodles when he calls. If the dish still tastes bad, you know it wasn’t because he got the wrong noodles.
What is a Spy?
Using spies is like giving your friend your phone number instead of the store’s phone number so that when he calls the store to order noodles, he calls you instead. That way you can verify that he’s ordering the right thing. If he calls and orders wheat noodles instead of rice noodles, you’ve found a bug with your friend’s recipe.
I also wrote Payton’s Testable Precepts: 10 guidelines I use when writing code that help make my code testable (as well as more clean, more flexible, and more readable). Here’s a list of those Precepts. See the slides for reasons and examples.
1. Always use classes, never global functions.
2. Don’t use static functions except as factories.
3. Use instance variables as constants.
4. Use filters to pass data indirectly.
5. Use verbs in all function names.
6. Keep functions below eight lines and indentation below four levels.
7. Consider all possible inputs and outputs.
8. Whenever possible, write tests first.
9. Don’t test the code from other libraries, but test the inputs and outputs.
10. Write only one assertion per test.