Proper and fast unit tests in WordPress

There were unit tests missing in my hacktoberfest project. Unfortunately there is no framework which does proper unit tests for WordPress plugins or themes. Most of them do integration tests so I made another approach to speed up tests and keep them very modular. Read the more up to date and famous one afterwards!
Recent changes with WordPress 4.7
Open in new tab for later

How do you test your code? Am I missing a framework?
Then please let me know in the comments.

You are not doing unit tests

Wow. This was harsh, condemned devs wholesale and is just unfair. But this is how I feel every day doing tests in WordPress. Today I found a solution and it feels great!

Every second dev, I would say, keeps messing terms up. Either you do proper unit tests or you were doing integrations tests all the time. Give me a minute to split that up.

Unit tests are testing a unit

Unit tests have established themselves as very modular tests for a single class or function. Once you break that barrier it is no longer a unit test.

They should run in no time. Single tests (those “testFooDoesBar()” functions) should run 0,1 seconds at most. The best case is that the whole testing is done within less than 5 seconds. Because usually you like to do them before each commit or push and don’t like to wait so long.

Lets examine this piece of code:

function get_more_recent_post_rand( $date ) {
  $posts = get_posts( [
    'date_query' => [ 'after' => $date ]
  ] );
  
  return array_rand( $posts );
}

Our unit is the “get_more_recent_post_rand” function which brings in another unit named “WordPress” by using the get_posts function. This functions needs to be mocked somehow for keeping it a proper unit tests. PHPUnit and Codeception are tools that can do such things.

What most tests tend to do is bootstrapping whole WordPress to have all it’s functions. Please don’t do that if you want to do unit tests. Adding another component without mocks makes it an integration test.

Integration tests are testing the integration

Rest assured that I double checked by asking friends of the PHPUnit community. Jakub Zalas, a developer at Sensio Labs responsible for Symfony and PHPSpec, answered:

if tests load a whole framework they’re not unit tests 😀

Very good condensed where unit tests end and integration tests start. As I already mentioned: Most of us tend to load the whole WordPress while bootstrapping. Okay, you can do that but then the tests are on the integration level.

Integration tests are more complex because they rely on anything third-party. Including some other frameworks, using adapter to the file system, a network, a tea pot or anything else means integrating your code into another environment. These are multiple units which often need much more time. It can take seconds to minutes and even days in some bigger applications.

The big difference and beyond

Beyond there are regression tests which simply means running some tests again. This is done everytime a developer changes something to assure that all features written before are still working fine.

Acceptance tests are something that the stakeholder or subjects can do. In my case I use modified Behat tests before a stakeholder starts with his acceptance test. It can run all tests a bit slower measuring the time a real user would use for finding an element, moving the mouse to it or typing in something. Because user experience is not only good when everything works but also when its fast.

Final solution: Between unit and integration test

This is a blog about WordPress, especially the Core, so lets get it straight. Most tests out there are integration tests. If they should turn into real unit tests it would be a really big effort. I found something in between which is an easy step towards real unit tests for your plugin or theme.

Shut down WordPress

Or most part of it. The “SHORTINIT” constant loads only a very little part of WordPress and not the whole complex thing. This makes tests a lot more faster and the additional unit called “WordPress” is not that big anymore. So write this in your bootstrapping before loading WordPress:

define( 'SHORTINIT', true );

After that my WordPress only took 0,01 seconds to load and only some of my tests failed. Solve that by either a require_once of some files / classes you need or mocking the missing functions. Mockery is very powerful for that. There is also BrainMonkey which helps a little bit with testing WordPress.

Or just turn off the lights

When you want to do some integration tests but do not need the theme then add this constant in the bootstrapping process:

// Hey, who turned out the lights?
define( 'WP_USE_THEMES', false );

Now it takes 0,25 seconds for WordPress to load which is okay. Most of WordPress with all its installed plugins is available now. Very nice if you like to check your plugin against other ones.

Place it in your PHPUnit config

I like to have it in the bootstrap process which looks like this:

//define( 'SHORTINIT', true );
define( 'WP_USE_THEMES', false );

$dir = __DIR__;

while ( dirname( $dir ) != $dir && $dir = dirname( $dir ) ) {
   $wp_load = $dir . DIRECTORY_SEPARATOR . 'wp-load.php';

   if ( file_exists( $wp_load ) ) {
      require_once $wp_load;
      break;
   }
}

But it can also be placed in the phpunit.xml configuration:

<php>
    <const name="SHORTINIT" value="true" />
</php>

A bit nerdy and fancy. I like it in the XML config because that way I can have multiple phpunit configurations. One for unit tests and one for integration tests.

Conclusion

I am old. Now 15 years into developing stuff and it is interesting how many you know and how many you don’t know – I still make mistakes. But I thank you for reading and I like that the thousands of people (reading this blog) now know the difference. Hopefully you call it integration test from now on. And I am sure that the bootstrapping of your tests have become much more faster.

What do you think about testing? Is it even worth it? Are you doing unit or integrations tests? Please leave a comment and lets discuss this a bit more.

Btw: Stay tuned to know more about the theme. A blog post will follow in the weekend.

Leave a Reply

Your email address will not be published. Required fields are marked *