Categories
Testing

Unit testing a WordPress plugin

Tests are an important part of the workflow of every project. They help us to verify everything is working as expected after applying changes to our code and give us the trust to publish them safely.

They also allow us to improve our productivity and deliverability by automating the testing task and setting us free to focus on adding new features.

There are different types of tests we can perform in a project: Unit tests, functional or end-to-end tests, etc., and apply multiple development methodologies based on tests like Test-Driven Development (TDD) or Behaviour-Driven Development (BDD).

Talking about all these concepts would be extremely large, so I left it in the reader’s hands to look into them.

This time, I will focus on explaining how to apply Unit tests to a WordPress plugin. A less-discussed topic, but it’s gained popularity and adepts in recent years.

Why unit tests?

As I mentioned, there are many types of tests we can perform over a codebase, so why start with the unit tests? Well, in my honest opinion, here are the reasons:

  • It’s the easiest way to introduce ourselves in the testing world.
  • Don’t require a complex setup.
  • You can apply them progressively to new and already existing projects.
  • It will change the way you write the code.

The three first reasons are self-explained, but I would like to stop to talk about the last reason in depth.

Writing the tests first and knowing what you want to test, the code that needs to pass these tests will be more testable and less bloated.

Juan José González

That quote, written in my own words, summarizes the TDD methodology and the principles it is based on. So trust me if I tell you writing tests will change how you write the code.

Unit tests scaffold

There are many libraries and frameworks for unit testing your code. The most popular frameworks right now are PHPUnit and Pest.

Of course, you can use whatever you want, but I will use PHPUnit in this post because, as you might be thinking, WordPress also has unit tests, and they are built with PHPUnit.

This is great because the core team has already created tools and libraries on top of PHPUnit to make our lives easier. So let’s get started:

In your WordPress plugin directory, execute the command:

wp scaffold plugin-tests sample-plugin

Note: Replace sample-plugin with the slug of your plugin.

If you don’t have the wp command available on your computer, install WP CLI first.

After running the command above, your plugin will include all the necessary files to start writing unit tests. More info here.

Now, every time we start our programming session and want to run some tests, we need to execute the script bin/install-wp-tests.sh. This will set up the WordPress testing environment, including the database.

bin/install-wp-tests.sh wordpress_test root root localhost latest

But wait, we haven’t installed PHPUnit yet. Well, we can do it globally or in the composer.json file of our plugin.

{
    "name": "juagonala/sample-plugin",
    "description": "Sample plugin",
    "type": "wordpress-plugin",
    "license": "GPL-3.0-or-later",
    "prefer-stable": true,
    "minimum-stability": "stable",
    "require-dev": {
        "phpunit/phpunit": "^9.5",
        "yoast/phpunit-polyfills": "^1.0"
    },
    "scripts": {
        "test-install": [
           "\"bin/install-wp-tests.sh\" wordpress_test root root localhost latest"
        ],
        "test": [
           "phpunit"
        ]
    }
}

As you can see above, I required PHPUnit as a development dependency. I also installed a polyfills package from the Yoast team that will allow us to use the latest version of PHPUnit (v9 at this moment) and, simultaneously, make our tests compatible with older PHPUnit versions.

Finally, I added a few scripts to the Composer file to install and run the tests easier.

Now run:

composer test

The output will be something like this:

> phpunit
Installing...
Running as single site... To run multisite, use -c tests/phpunit/multisite.xml
Not running ajax tests. To execute these, use --group ajax.
Not running ms-files tests. To execute these, use --group ms-files.
Not running external-http tests. To execute these, use --group external-http.
PHPUnit 9.5.24

No tests executed!

Good, it’s working, but no tests were executed. That’s because we haven’t written any tests yet, so let’s create our first unit test!

Creating unit tests

Under the tests/ directory, create a file called test-sample-plugin.php with the following content:

<?php
/**
 * Class SamplePluginTest
 *
 * @package Sample_Plugin
 */

/**
 * Sample plugin test case.
 */
class SamplePluginTest extends WP_UnitTestCase {

	/**
	 * A single example test.
	 */
	public function test_sample() {
		$this->assertTrue( true );
	}
}

Let’s digest the code of the test file:

First of all, we see it contains a class called SamplePluginTest that extends the class WP_UnitTestCase. The name of our class is indifferent, but the class it extends it’s important.

The class WP_UnitTestCase contains all the necessary methods for performing tests and allows us to initialize the environment in case our tests need special conditions or configurations.

Next, the method test_sample(). The prefix test_ is important here because PHPUnit only calls methods starting with this prefix. Inside this method is where we must place the tests.

In our sample, it just checks the provided value is true, and as the first argument of the method assertTrue() is true, the test will always pass the assertion.

Now, let’s execute our tests again:

composer test

This time, the console outputs the following result:

> phpunit
Installing...
Running as single site... To run multisite, use -c tests/phpunit/multisite.xml
Not running ajax tests. To execute these, use --group ajax.
Not running ms-files tests. To execute these, use --group ms-files.
Not running external-http tests. To execute these, use --group external-http.
PHPUnit 9.5.24

.                                                                   1 / 1 (100%)

Time: 00:00.017, Memory: 36.00 MB

OK (1 test, 1 assertion)

Yes, we did it! We created our first unit test. Well, this test is trivial and useless, but I’m sure you got what comes now.

PHPUnit has tons of assertX() methods, so I invite you to look at the complete list. And don’t forget we are using WordPress over PHPUnit, so it’s very likely the core team added its assertion methods.

The class WP_UnitTestCase is an extended version of the class PHPUnit_TestCase, simplifying the task of initializing the WordPress environment. So, feel free to take a look at its code too.

Grouping the tests

As I mentioned before, the methods starting with test_ contain the tests, but you shouldn’t place all tests in a single method!

You can add as many test_ methods as you want in a TestCase class, but normally, tests are grouped by functionality.

It’s common to see together assertions for a specific function or method. That’s why the code for initialing the environment is the same for all of them.

Additionally, you can split tests into several files. Once again, it’s a good practice that for each class of our project, exists a class that tests it.

The PHPUnit.xml config file

The phpunit.xml is the configuration file for PHPUnit and allows us to define many aspects of our test suite. For example:

  • The location of the bootstrap file.
  • Where the test files are located and what files to ignore.
  • The console’s output.
  • Etc.

The possibilities it offers are quite large, but fortunately, the configuration generated with the scaffold command is enough for our needs.

The bootstrap file

When talking about the phpunit.xml config file, I mentioned there is an option to define the location of the bootstrap file. But what is this file for?

This file was added when we executed the scaffold command, and you can find it in tests/bootstrap.php. It’s quite important because it is in charge of initialing all our testing environment. Including the WordPress PHPUnit library, and loading our plugin inside it.

Once again, I invite you to look at the code of this file. Maybe you want to apply some tweaks to it.

Final tweaks

We have seen that by executing just a single command, we can get the setup for writing tests in our plugin.

At this point, I’ll give you the final tweaks I like to apply to my projects. Of course, this part is quite personal, so it’s up to you to apply them.

  1. The first tweak is to move all the test-related code inside the tests/ directory. That includes the script bin/install-wp-tests.sh.
  2. Next, not all files included in the directory tests/ have to contain tests, so I prefer to move these files to tests/unit-tests/.
  3. Now that test files are located under a single directory, I’m free to use a different naming convention than the rest of the plugin files. For example, the PSR-4 Standard.
  4. Finally, I clean all files I won’t use. For example, .travis.yml. I prefer GitHub Actions for CI/CD.

And that’s all.

In conclusion

We have seen how to add unit tests to a WordPress plugin from scratch and how to run them, reviewed the different config files, and made a few recommendations we can apply to our setup.

Now, it’s time to put all of this into practice. Remember, you can add unit tests to your projects progressively. There is no need to test everything, just the new changes you apply to your code.

It’s never too late to add tests to a project, and I hope this post gave you the knowledge and confidence to help you achieve this goal.

So, there is no excuse for not testing your plugins right now!

Juan José

By Juan José

Building amazing products for WordPress & WooCommerce since 2012.