September 28, 2020

While many of us have heard of unit testing, it’s not a big topic of discussion in the WordPress community. Yes, there are tests for WordPress core. Yes, many of the major plugins like WooCommerce have unit tests, but that doesn’t make it easy to jump on the unit testing train.

While you can find lots of content about unit testing PHP applications, there aren’t many people talking about unit testing specifically for WordPress. There is precious little written about where to start for developers that are ready to increase their code quality and want to learn how to add tests to their work. Even worse, some of the tools for unit testing in WordPress don’t work as advertised, or are using older versions of PHPUnit. Problems you’ll have to discover on your own as you try to start testing.

That leaves many people who want to get started with testing on a multi-hour journey to get even the basic default tests running for their plugin.

Today we’re going to solve that problem by giving you an up-to-date look at how to start unit testing your WordPress code.

Things to Have Installed

Before we dive into unit testing, I’m going to assume you have Laravel Valet and WP CLI installed. I use these excellent directions from WP Beaches to install Valet, though I use the mysql instructions not the MariaDB ones.

You can find the instructions to install WP CLI on the WP CLI site.

If you’re on Windows, you may have a bit of extra digging to do so you can run unit tests. The WordPress Handbook has some instructions on the extra steps you’ll need to take.

Install PHPUnit for WordPress on Laravel Valet

Our first step is to install PHPUnit. While PHPUnit is currently on the 9.x branch, WordPress only supports 7.5.x which means we’ll need to install this older version.

Open up the terminal and use these commands.

wget https://phar.phpunit.de/phpunit-7.5.9.phar

chmod +x phpunit-7.5.9.phar`

sudo mv phpunit-7.5.9.phar /usr/local/bin/phpunit

phpunit --version

The command above, download PHPUnit. Then we make the file executable so it can be run. Next, we use the sudo command to move the file to the proper location on our computer. Finally, we check for the version number, which should return 7.5.9 when we run the final command.

Now we’re ready to set up our plugin with WP CLI and take a look at our first tests.

Setting Up Our Plugin

We can make starting a plugin, and getting our unit test scaffold, easy with the WP CLI scaffold command. This command will create a plugin for us, and add all the files we need to have a foundation for our tests.

In the terminal, make sure you’re in the proper WordPress directory you want to use and then type wp scaffold nexcess-unit-tests. That should give you a folder structure that looks like this.

– bin

– install-wp-tests.sh

– tests

– bootstrap.php

– test-sample.php

– .distignore

– .editorconfig

– .phpcs.xml.dist

– .travis.yml

– Gruntfile.js

– nexcess-unit-tests.php

– package.json

– phpunit.xml.dist

– readme.txt

If you want to build out the basics of a plugin but not include tests then you’d use the –skip-tests flag, which will skip the generation of test files. You can see all the options available for this command in the WP CLI documentation.

Depending on how your code editor and file system are set, you may not see the files that begin with a . because they’re considered hidden files. For our purposes today, they don’t matter so don’t worry about it if you don’t see them.

Now we need to hook our unit tests up to MySQL so that it can create dummy data for us to test against. Open up the wp-config.php file for your WordPress installation now because you’re going to need to find the db_user and db_pass for the next command.

To finish installing the tests change to your plugin directory and run the following command.

bin/install-wp-tests.sh localhost latest

Make sure you use a different db-name than your WordPress install. You don’t want your unit tests messing with your data, you want it creating its own test data in its own database. Otherwise, the db-user and db-pass will be the same as your wp-config.php file.

The final two parameters tell the testing framework to connect to localhost and to install the latest version of WordPress to test with. Unless you know better, just leave those settings as they are.

If we were to run phpunit now, we’d still have a few errors to resolve. First, for some reason WP CLI doesn’t add the name attribute to the block in the sample tests. Open phpunit.xml.dist and change to and save the file.

Also note here that inside the block PHPUnit is told to ignore the tests/test-sample.php file. Let’s duplicate that file and rename it to test-nexcess.php so that we have a file which will run. Then open the new file and change the class name to NexcessTest. The file should look like this now.

/**

* Class NexcessTest

*

* @package Nexcess_Unit_Tests

*/

/**

* Sample test case.

*/

class NexcessTest extends WP_UnitTestCase {

/**

* A single example test.

*/

public function test_sample() {

// Replace this with some actual testing code.

$this->assertTrue( true );

}

}

Now we’re ready to run phpunit from the terminal. Once you’ve done that you should see something like the image below.

Now that we’ve confirmed that PHPUnit is running our tests, let’s dive a little deeper and write a test to make sure that WordPress is adding users properly.

setUp and tearDown

Most unit tests will require specific data to be added to the testing database. Then you run your tests against this fake data. To do this you use the setUp and tearDown functions in your testing class.

Let’s create a user and then make sure that the user has the edit_posts capability. Add the following function to the top of your class.

public function setUp(){

// make a fake user

$this->author = new WP_User( $this->factory->user->create( array( 'role' => 'editor' ) ) );

}

Then add this tearDown function to the end of the class.

public function tearDown(){

parent::tearDown();

wp_delete_user($this->author->ID, true);

}

This adds a user with the role of editor before we run our tests, and then removes the user after we’ve run our tests.

Now let’s write a simple test to verify that the user was added properly and has the proper capabilities.

public function testUser(){

// make sure setUp user has the cap we want

$user = get_user_by( 'id', $this->author->ID );

$this->assertTrue( user_can( $user, 'edit_posts' ), 'The user does not have the edit_posts capability and they should not' );

$this->assertFalse( user_can( $user, 'activate_plugins' ), 'The user can activate plugins and the should not be able to' );

}

Above we start by getting the user object based on the fake user we created. We’ll need this object to test our capabilities which we do next with the assertTrue and assertFalse statements.

In this instance assertTrue is expecting that our user_can( $user, ‘edit_posts’ ) returns true. We’re testing to make sure that the user object provided is given the edit_posts capability, as an editor should have. If this were to return false, we’d see the message provided in our unit test output in the terminal.

Next, we test to make sure that the same user doesn’t have capabilities of an admin user. Here we use assertFalse while checking for the activate_plugins capability. This should return false because activate_plugins` is for the Admin role in WordPress not for Editors.

Once you have that code added after your setUp function, head to terminal and run phpunit. You should see 2 tests are okay, with 3 assertions.

PHPUnit considers our testUser function to be a test, and the assertTrue/assertFalse statements inside to be assertions.

What does that factory thing mean?

Before we finish here, let me draw your attention back to our setUp function. Specifically the factory section when we create a new user.

When you use the WP CLI scaffold, it gives you access to the WP_UnitTest_Factory class. This class is there as a helper to create the data you’ll need to run your tests properly. You can use this factory to create posts, attachments, comments, users, terms, and some other things for WordPress Multisite.

This is not the only tool you can use to mimic WordPress for your tests though. In a future post we’ll look at WP_Mock to test parts of WordPress that the built-in factory doesn’t reach very well.

Today, we covered a fair bit of complex ground as we looked at unit testing your WordPress projects. I know when I started unit testing it looked daunting, but it’s worth it if you want code that works, and lets you know when you’ve broken something, so your customers don’t have to find the problem for you. Over the long-term, you’ll save time and headaches by writing testable code and aiming for decent test coverage in your projects.

Improve your WordPress sites performance with fully managed WordPress hosting that scales as your website grows without compromising security. Learn more today.

Curtis McHale
Curtis McHale

Curtis is a husband, father, developer and business coach. He specializes in helping people build a business that lets them spend time with their family instead of working all the time.

We use cookies to understand how you interact with our site, to personalize and streamline your experience, and to tailor advertising. By continuing to use our site, you accept our use of cookies and accept our Privacy Policy.