The solution of our PHPUnit problem
In the previous post I gave you some homework, remember? Here’s what I asked you to do:
Rewrite the function
neliovat_get_vatso that money quantities expressed as strings like
3€(where the optional thousand separator is
., decimal separator is
,, there might be a currency symbol, and there aren’t any spaces) passes the test.
The original function I presented was:
and the failing test was:
So, how do we solve this? The idea is pretty simple—you have a string with some “extra” characters you have to get rid of (like the thousands separators or the currency) and change the decimal separator from a comma to a dot. If you do that, the number can be understood by PHP as a float number and, therefore, its VAT can be computed. The resulting function looks like this:
and the results you get after running the test again are:
If you’re wondering which one is better, there’s plenty of blog posts comparing them (and others). If you want my opinion, though, you should try them all and stick to the one that makes you the happiest. However, you might also want to take a look at QUnit.
Setting Up Our First QUnit Test
Let’s assume we have our beloved function
The tests we want this function to pass could be written as follows in a file named, for instance,
If we now open this document in our web browser, we’ll get the following:
which means all our tests were a complete success!
A Few Tips and Tricks to Become a Better Programmer and Tester
As you can see, there’s no magic behind unit tests—sure, there’s a lot of things we haven’t discussed yet (such as, for example, how to set up an environment with already-existing data), but it’s all about using the testing framework and its functionalities properly. Truth is, it doesn’t really matter the language you’re testing—what’s important is to believe in testing as a concept and try to be as efficient as possible when doing it.
The most difficult part is, as always, getting started and keep up with the initiative. Questions like “am I testing the right component?”, “am I forgetting about something important?”, “are these tests really useful?”, “would anyone care if I skip this test?”, and so on are not always easy to answer and the answers can be discouraging. But if you’re asking them yourself, at least it’s clear you care.
To answer most of them, I recommend you watch the following videos. I loved them both, and I still re-watch them from time to time.
In my opinion, the most interesting parts of his talk are:
- A good unit test has three basic properties (watch in the video)
- It’s TRUSTworthy. If the test tells you everything’s alright and you don’t trust it, you’ll want to recheck your code to make sure that, indeed, it is. Or if it tells you something isn’t right and you don’t believe it, you might be tempted to tell yourself “hey, tests sometimes fail; I’m sure everything’s alright”. See? If you don’t trust the results of your test, why would you bother to create them in the first place?
- It’s MAINTAINable. Tests will eventually change because your tested code will probably change too, so make sure they’re clean and clear. Don’t intermingle too much information in a unique test, keep them clean and short so that they can be easily adapted to your future needs.
- It’s READable. If a test fails, a programmer will want to know why. In other words, they’ll probably need to take a look at the test, read it, and understand what it was supposed to test (if it’s properly named, they might even be able to skip the source code). If your test can’t be read, you and future programmers will have trouble maintaining your code.
- Tests must be simple (watch in the video). The more code you add in a test, the more likely it is that the test itself will have bugs. And that’s kinda weird! You don’t want your test code to contain bugs itself. The easiest way to “guarantee” that is by writing simple tests. So try to write short, simple tests, with no loops, no if/else statements, etc.
- Use meaningful names (watch in the video). This is probably the most enlightening part of the video. If you really want people to understand what a test does, name it properly. To do so, make sure the following three facets are perfectly stated:
- Unit of Work: WHAT we are testing. This might be a class, a function, a module… whatever, but make sure it’s clearly stated.
- Scenario: WHEN and HOW we are running the test, what the context is. There are functions that behave exactly the same no matter what, others depend on the types of their attributes, others on the database state. For instance, saving a post that doesn’t exist behaves differently from saving a post that already exists, so that’s the scenario: are we saving a new instance or are we overwriting an already-existing instance?
- Expected Behavior: WHAT should (or shouldn’t) happen as the result of our test? The most important part here is to state that using the verbs SHOULD and SHOULDN’T. For instance, the following test is very clear: “Given the function
wp_post_save(unit of work), when we save an already-existing post (scenario), the post’s ID should be the same as it was before saving it (expected behavior)”. If, on the other hand, the expected behavior was states as “…, the post ID is the same as it was before saving it”, it’s not clear if we’re stating a problem (the post ID is the same, and it shouldn’t) or if we’re already stating what we expect.
The second video is very useful for beginners. I remember that one of the things I struggled the most when I started to test my code was the fact that it couldn’t be tested—my code wasn’t that complicated, but I didn’t know how I could test it!
A few minutes later, the speaker shows you the light and tells you how to write your test so that it becomes testable and, as a result, readable and maintainable:
- Use constructors to create instances
- Support configurability
- Keep methods simple
- Don’t intermingle responsibilities
I could try to summarize her thoughts about each guidelines, but I really, really encourage you to watch her explain them. If you do so, you’ll see how wonderful it is to apply them in your own work
Featured Image by etringita.