Unit Testing Themes and Plugins in WordPress

Nes_Test_Station

Over the past few weeks, we’ve been investigating the best way to incorporate a WordPress testing framework into our development process. With few developers out there writing tests for their plugins (and even fewer testing themes), we want to share our tribulations as we figure the process out.

Fortunately, WordPress ships and supports a unit testing framework. Unfortunately, this framework is designed mainly for development on WordPress core and not directly for WordPress plugin and theme developers. However, with enough prodding, it is possible to write your own tests on top of this library.

Step one: Installing PHPUnit

The PHPUnit library provides a base framework for writing tests in PHP. WordPress develops its own testing platform on top of this library.

Assuming you’re on a *nix system, installing PHPUnit is as simple as:

wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit

See the PHPUnit installation notes for installing the framework on Windows or including it with composer.

Step two: Pull in the WordPress framework

Before we go any further, I should note that wp-cli ships with a handy command that does a lot of this grunt work for you. However, it currently supports tests for plugins only (not themes). If that’s all you need, it’s the fastest way to get started, but the steps below should give you a better understanding of what’s happening behind the scenes and give you a setup that can be customized for your specific development environment.

WordPress bundles its testing framework in with its core development tools svn repo. We can download just the tools we want by checking out the includes directory. It’s up to you where you want to organize your testing library. For the sake of this tutorial, we’ll assume you clone it into your root WordPress directory.

cd <wproot>
svn co http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/

You’ll need a second WordPress config file named wp-tests-config.php as defined here:

https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php

Configure the database details as you would a normal wp-config.php. It’s important to use a secondary database, as WordPress drops and recreates tables as part of its tests. In addition, ensure that ABSPATH is pointed to the correct WordPress install to use during testing.

Step three: Hook it all together

What we do now is create a phpunit.xml file. This file is what PHPUnit uses to load the testing environment and run its tests. It doesn’t matter where you create this file, but for the sake of this tutorial we’ll add it to the WordPress root directory (the same place we downloaded the WordPress test framework).

<phpunit 
	bootstrap=“./includes/bootstrap.php"
	backupGlobals="false"
	colors="true"
	convertErrorsToExceptions="true"
	convertNoticesToExceptions="true"
	convertWarningsToExceptions="true">
	<testsuites>
		<testsuite>
			<directory prefix="test-" suffix=".php">./tests/</directory>
		</testsuite>
	</testsuites>
</phpunit>

Now, if you run PHPUnit from the command line —

cd <wproot>
phpunit

— you should see this on the command line.

no-tests

If errors are thrown, check that your paths all point to the correct place.

Step four: Building tests

What we’ve got so far is the included framework that ships with WordPress. First, our phpunit.xml file is specifying a bootstrap.php file to load and install WordPress. Then, it's looking in ./tests/ for files in the format test-*.php to run actual tests. Since we don’t have any tests yet, no tests are executed.

This base configuration is only running tests on WordPress core functions. In order to test our own plugin and theme functions, we must create our own bootstrap.php file to specify which theme and plugins to activate before installing WordPress. Create a new file called ./tests/bootstrap.php. In this file, include the following:

<?php

require_once dirname( dirname( __FILE__ ) ) . '/includes/functions.php';

function _manually_load_environment() {
	
	// Add your theme …
	switch_theme(‘your-theme-name‘);
	
	// Update array with plugins to include ...
	$plugins_to_active = array(
		‘your-plugin/your-plugin.php’
	);

	update_option( 'active_plugins', $plugins_to_active );

}
tests_add_filter( 'muplugins_loaded', '_manually_load_environment' );

require dirname( dirname( __FILE__ ) ) . '/includes/bootstrap.php';

Update your phpunit.xml file to include this new bootstrap file, instead of the WordPress default.

Now you have everything you need to write unit tests on your theme. Create a new file named ./tests/test-sample.php and write your first test:

<?php
class SampleTest extends WP_UnitTestCase {
	function testSample() {
		$this->assertTrue( 'Your Theme' == wp_get_theme() );
		$this->assertTrue( is_plugin_active('your-plugin/your-plugin.php') );
	}
}

Running phpunit now, you should see the following:

tests

That’s it! You’re now able to write your own test functions to test your code.

Final words

It’s important to note that while this is one way to organize your testing code, it might not be the best for your development environment. You might, for example, prefer to keep your test suite (./tests/) in the root of a theme or plugin directory, so that it is included in version control. Or you might want to keep tests completely outside of the WordPress directory.

Diving deeper, you might want to activate and deactivate plugins directly in the testing classes to test what happens when plugins aren’t loaded. You might want to maintain multiple test suites for different plugins or themes.

Lastly, now that you are set up to write unit tests, you might be asking how you should go about writing a test. We’ll cover some unit testing best practices over the coming weeks as we write our own tests for our codebase. For now, take a look at some test classes that WordPress has written to get a feel for how tests are built.

  • Hats off friends. It is really a big efforts in WordPress. As a WordPress developer, I know that how difficult
    it is to test a WordPress core and WordPress plugins.
    Keep it up, waiting for next article.

    Regards
    Amy

  • Rafaella Keury

    It keeps giving me: ‘Fatal error: class WP_UnitTestCase not found in test-sample.php on line 2’

  • Greg

    Oh god that helped me so much, big thanks to you!

  • William Gu

    Thank you so much, best tutorial instructions after suffering hours looking online for a clear guide on how to achieve this.

  • Alex Nitsa

    Hi there…

    I have this error while running phpunit

    “`
    PHP Fatal error: __clone method called on non-object in /var/www/html/wordpress/includes/testcase.php on line 238
    “`

    Can you assist?

    Thank you,
    Alex

  • Alex Nitsa

    Hi,

    How can I test if a custom post type exists?

    Thank you very much.

    Cheers,
    Alex