Late last month, I started talking about writing unit tests in PHPUnit for WordPress-based code. This primarily included the idea of setting up PHPUnit, the setUp function, and writing basic tests.
This did not, however, discuss what I know about the tearDown function which is still an important feature of writing using tests. Further, there’s also two ways to consider writing tests for WordPress projects.
- writing tests specifically for plugins and application-layer functionality,
- running unit tests against the WordPress application.
Before moving forward with this particular post, though, I recommend catching up on what I’ve covered thus far. This includes the following posts:
- A WordPress Development Environment (Using a Package Manager)
- An IDE for WordPress Development
- Working with User Settings in Visual Studio Code
- Writing Unit Tests with PHPUnit, Part 1: The Set Up
Once you’ve done that, return to this post and let’s continue discussing the tearDown function and what unit tests in the context of WordPress actually look like.
Unit Tests with PHPUnit, Part 2: The Tear Down
Before moving forward, remember that developers often treat the setUp function like the constructor and the tearDown function like a destructor; however, remember that the latter is not always needed.
Here’s a good rule of thumb to remember:
- Anything a test function needs will call the setUp function so that necessary classes are needed.
- The tearDown function is not always needed since the setUp function can reinitialize a class.
So what does this mean for the tearDown function if it’s not resetting data that’s created during the setUp function?
1. The tearDown Function
The best advice that I can give around the tearDown function is that it should be used if something is set up during one of the tests that is left behind.
This might be something that’s written to a database, something that’s written to a log, or, more generally, something that’s written to the hard drive.
Thus, if a test write a record or a file, the tearDown method will run after a test and should remove whatever a test recorded to the drive that isn’t part of the test but isn’t permanently needed for the next test or that should be cleaned up after itself.
So in a sense, it’s like a destructor but if you’ve never used a language that has a destructor that nomenclature either seems irrelevant or doesn’t make sense.
A destructor is a special member function that is called when the lifetime of an object ends. The purpose of the destructor is to free the resources that the object may have acquired during its lifetime.
Thus, perhaps it’s better to simply think of the function as a way of cleaning up after a test (and not in the sense of setting a variable equal to null since the setUp function can do that).
2. Unit Tests for WordPress Projects
When writing unit tests for WordPress projects, we have to make sure that we’re being clear about the type of unit tests about which we’re talking.
For example, what I’ll refer to as classical or standard unit tests follow the “test-driven development” methodology which I’ll talk about in a moment. On the other hand, WordPress has its own set of unit tests for themes and the like which I’ll also talk about a bit later in this post.
But for this section, I thought it might be helpful to talk a bit about the former rather than the latter so you can see how this might work.
In the example below, I’m writing tests against a plugin that’s responsible for communicating with a third-party API. This particular plugin requires a username and password or an API and it we want to make sure that, for the purposes of this post, it’s properly retrieving an error whenever the test is run.
Note that when reading through this code, you’re going to see me talk a bit about reflection. I’m going to do an entire post on PHP Reflection soon so it will be shed some light on this.
For the code below, though, assume it’s a way that we’re able to gain access to properties that are otherwise marked as private.
Recall from the last post in this series, we had an initial test that looked like this:
Notice, however, in this test there is no tearDown function which makes sense, right? After all, nothing is being written to a database or to a file.
But let’s say we want to introduce a test case that’s going to have a filename, content, and its going to write the content to the file. In this case, it’s going to be static data but this could technically be anything that’s written to disk.
1. Setting up the Test
First, we want to setup the test by defining the filename, the content of the file, and preparing the properties.
Easy enough, right?
2. Write and Read Data
Next, we want to write the data, read the data, and assert that the contents are the same.
At this point, if you run the test (which I’ve not yet technically covered on how to do), you’ll notice that testFile.txt still resides on your system.
3. Using tearDown
Finally, we need to work with the tearDown method to make sure the file is deleted upon completion of the unit test. Here’s how it may look if you’ve implemented your code like what you see above.
Notice that in the tearDown method, I first check to see if a file_exists. This is because if you simply attempt to unlink a file that isn’t present, you’ll get an error when running your tests because if tearDown is present, then it’s going to try to delete something after every single test function. And if the file doesn’t exist, then there’s nothing for it to delete, and thus it will result a problem.
So in attempt to write code defensively, I believe it’s responsible for checking if the file exists before actually trying to delete it.
3. Order of Operations
When it comes to pure unit testing, you’re normally going to read this in terms of test-driven development. This is a big topic in and of itself; however, it’s worth mentioning here should you opt to research it further and even implement it in your development efforts.
The general idea behind this approach is often referred to as “red-green-repeat.” And I’m not denying it, there’s something to this approach. Namely, it allows you, as the developer, to write code as you expect it to work before actually writing the code.
The psychology behind it is this: If you know how the code works, you’re more likely to write tests that pass; whereas, if you write tests for how the code should perform, you should write better code.
Unfortunately, we’re not always afforded that luxury. But that doesn’t mean we should throw the proverbial baby out with the water. Instead, I’m of the mindset that you should write tests when you can and write the code afterwards; otherwise, write your tests after your code.
Ultimately, having testing in place regardless is going to be better than no tests at all.
4. Testing with WordPress
When it comes to unit testing in WordPress, there’s a few things that you’ve likely stumbled across. Sometimes, the content is a misnomer or may be even misleading in terms of “unit testing in WordPress.”
Case in point, there are two things worth noting:
- The Theme Unit Test. This particular set of content is meant to help theme developers test all of the major and minor cases for their themes. There’s aren’t automated tools, for example, that you’d use like in what we’ve discussed above.
- Automated Testing. WordPress ships with its own set of unit tests so that we don’t have to write tests against most of the functionality in WordPress (like whether or not API functions work as expected). This allows us to focus on writing unit tests for our own domain logic.
- Plugin Unit Tests. If you’ve used WP-CLI (or are interested in it), then you’ve likely read this page or even used this tooling. It’s useful, but it’s also targeting specific aspects of testing WordPress plugins.
All of the above is useful information, and I’m not saying that it should be ignored. Instead, it should be coupled with the rest of the information used throughout this post.
Running Unit Tests
In the next post, I’ll walk you through everything you need to know to setup an XML file that will inform PHPUnit of where the tests reside and how to run them.
For now, though, review the code that’s in this post and prepare to build off of it in the next post in this series.