Writing Integration tests in WordPress

Integration testing, like unit testing, is a best practice with the goal of evaluating a piece of software’s ability to interface with the rest of a system. Earlier I elaborated on the distinction between integration and unit testing and I won’t repeat myself here. Instead I’ll briefly expand our definition of integration test and demonstrate how to use the WordPress Unit Test Suite to test a plugin.

What’s an Integration Test?

Tests which execute your code directly to determine if it properly interfaces with its dependencies are called integration tests. They require the greater system be installed in order to verify where a failure might occur. Unlike unit tests, integration tests do not necessarily test the correctness of your code as much as they do the system’s stability and your code’s interaction with it. For example, if we’re building a method to save data passed through a POST request into a database, a unit test would demonstrate that our method prepares that data appropriately and calls the correct methods for saving the data. An integration test would actually instantiate the database and save the record. For this reason, integration tests are more expensive. You’ll recall that the WordPress Unit Test Suite (WUTS) requires a dedicated MySQL database and a working copy of WordPress in order to execute tests. Reading and writing from MySQL can be an intensive process.

For a plugin we are developing at my client, we had five tests that verified a feature. With WPUTS, the tests took nearly 42MB of memory out of our server, when we tested the same feature with unit tests, we shaved it down to 8, about a 5.25x improvement. The unit tests might be faster, but the data gleaned from an integration test is valuable in its own right. How else do you evaluate why a plugin fails when all of its unit tests pass? Perhaps it’s because you are sending the wrong data to the methods you’re mocking. Integration tests will catch that, unit tests won’t.

How to do it

First install WP-CLI as it will make everything much easier. The directions on getting the plugin tests initialized through WP-CLI are very clear and I won’t repeat them here. This will install a separate copy of WordPress and a separate database for testing. If you run phpunit from your root directory, you should output similar to this travis build. Passing tests validate the stability of WordPress, the failing and skipped tests are either incomplete or anticipate features in development. The tests will probably take under two minutes to execute depending on your system. If you cd into wp-content/plugins/your-plugin you should see a tests directory, a phpunit.xml file, and a bootstrap.php inside the tests directory. Run phpunit from your plugin’s root directory and it will execute any files which begin with ‘test-‘ and end with ‘.php’. Go ahead and create a test-your-plugin.php file inside the tests directory.

ProTip:To change which files phpunit will pick up when you run it, modify the bootstrap.php file.

Your first test

As we did with unit testing, let’s start with a simple test we know will always pass. You’re going to want to first extend the WordPress unit test suite:

class YourPluginTests extends WP_UnitTestCase {

}

Then inside that class, write a simple test:

function testIsAlwaysTrue() {
    // Arrange
    $foo = true;

    //Assert
    $this->;assertTrue($foo);
}

`$foo` will always be true and that test should pass if you run phpunit. Now let’s take a look at some of the features the WPUTS has to offer.

The factory

WPUTS has a factory for creating things you might need for your tests. Let’s say we’re writing a method to check the title of a post. Since we have none, WPUTS should create one for us. Let’s write a test that checks if a newly created post has a title.

function testPostHasTitle() {
    // Arrange
    $post_id = $this->factory->post->create();

    // Act
    $post = get_post($post_id);

    // Assert
    $this->assertTrue(!empty($post->title));
}

That’s a fine looking test, and it passes! But what does it tell you? Does it verify the `get_post()` method? In some ways it does, but it certainly doesn’t verify all of `get_post()`. In this case it mostly verifies that a post can be fetched out of the database. Let’s take the same method [we verified earlier][4] and write an integration test for it, only this time we won’t mock it. We’ll start with the same name:

public function testTestPostExpectsMetaDataSaved(){

}

In our arrange section we’ll use the factory to create a post, and we won’t do any mocking. Remember, we’re interested in whether the system is functioning with our code in it. Our arrangement, in this case, will also include a variable `$expected` we will use in the assert section. The act section will be mostly the same, and the assert section will contain a check to `get_post_meta` and an `assertEquals` statement compairing $expected and our result. If all is well with our `save_meta_data` and the WordPress methods used in it, they should be the same. We can also write a message to print if the test fails.

// arrange
    $post_id = $this->factory->post->create();
    $expected = 'New meta value'

    // Act
    $methods = new MetaMethods();
    $methods->save_meta_data($post_id);

    // Assert
    $actual = get_post_meta($post_id);
    $this->assertEquals(
      $expected,
      $actual,
      'Meta data expected to equal ' . $expected . ' but instead was ' . $actual);

If we run the test now, it will either fail or error out because we haven’t written $methods->save_meta_data yet. Our development goal: make the test pass. Once this test passes, we can say, with a bit more certainty, that our method saves meta data properly.

Unit and integration testing are similar but one distinct advantage of integration testing is that we can use the testing environment to experiment with core WordPress functions. We can use it to get under the hood, as it were, without digging through the codex and StackOverflow. If your unit tests are passing but your plugin isn’t working, try running an integration test and see if maybe you’re not feeding the mocked function the proper data.

Testing of any kind allows you to think carefully about what your method should do and how to make it happen. Do you need a full post object, or do you need only the ID? Do you need all those conditionals? How much work is this method actually doing? The more you test, the simpler your code will be. Simpler code is easier to test, troubleshoot, and extend. It is important, however, to be mindful of the differences between the two concepts as they have implications for what you can and can’t say for certain about your code.

As before, our full test is below:

class YourPluginTests extends WP_UnitTestCase {
    function testPostHasTitle() {
        // Arrange
        $post_id = $this->factory->post->create();

        // Act
        $post = get_post($post_id);

        // Assert
        $this->assertTrue(!empty($post->title));
    }

    public function testTestPostExpectsMetaDataSaved(){
        // arrange
        $post_id = $this->factory->post->create();
        $expected = 'New meta value'

        // Act
        $methods = new MetaMethods();
        $methods->save_meta_data($post_id);

        // Assert
        $actual = get_post_meta($post_id);
        $this->assertEquals(
          $expected,
          $actual,
          'Meta data expected to equal ' . $expected . ' but instead was ' . $actual);
    }
}

Using Composer to Manage a WordPress Installation

The team at Roots.io have a fantastic walkthrough of Composer and why and how you should use it in managing a WordPress site. Composer is a wonderful piece of technology that reduces the headache of figuring out how to managing the individual components of your site to a single file and software solution. With WordPress, a utility like composer breaks an installation into discrete pieces. This allows you to automate deployments and updates of your site using only the composer.json file and isolating each part of your site to its own maintainable place. I plan to make composer-automated installations the default on all future WordPress projects I undertake.

Octopress: Six Months Later

When I was a week into this blog, I wrote down some of the reasons I liked Octopress, my initial impressions of it as a blogging platform and whether it could compete or replace WordPress. It was a leap for me, a WordPress developer and long time fan of the platform. In general I have found Octopress to be an interesting experiment in hacker blogging but am back to WordPress as of this entry.<!–more–>

Starting, as before, with what I (still) like about Octopress. There is still a lot to like.

  1. I love writing in Markdown. WordPress.com recently added Markdown support, so it’s only a matter of time before I can write in Markdown here without a plugin, but being able to practice What You See is What You Mean (WYSIWYM) while blogging without writing straight HTML is really quite convenient. When I write on WordPress blogs at work I often forget it’s either straight HTML (too cumbersome) or the TinyMCE What You See Is What You Get (WYSIWYG) editor (too unreliable).
  2. Simple local previews are another thing I really love. rake preview is up there with Django’s ./manage.py runserver test server in simplicity. What I would change is that the rake server is not nearly as competent as Django’s when it comes to compiling sites after making changes and letting you know about errors. For example, using quotation marks in categories causes errors in site generation with Octopress but the only output in the preview terminal is the somewhat unhelpful WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true. Nevertheless it is quite simple to get a full, local, site preview while you’re still editing.
  3. Accidental publishing happens less frequently. This relates to 2 in that you have to be pretty deliberate about publishing the post for the world to see. Saving the file locally preserves your work. rake preview let’s you see it in a browser (almost) exactly as it should appear. Getting it out in the public, however requires rake gen_deploy run from the terminal.

With all that said, Octopress has a long way to go. Most of what I missed is WordPress’s user interface and content management features.

  1. Drafting posts. In WordPress, your post isn’t given a published date until you hit Publish, at which point it records the exact moment in time you hit publish as the date posted. In Octopress, this timestamp is added as soon as you execute rake new_post[]. I’m a drafter. Sometimes I’ll start three blog posts at once to get some ideas on the page and then put them aside until I have time work on them. (I started this one on January 1 and look at me now.) December 23, for example, I wrote Why Unit Testing Matters in one go. But I also started two follow on posts about writing good unit and integration tests. I ran rake new_post three times and each post had the same publish date even though the last two hadn’t been published yet! When I rake deployed, I had the post I wanted buried under two empty posts. When I finally finished the first of the others it was 2014 and I had to manually change the date and time as well as the published status. Manually managing these publish times was a bit of a nightmare.
  2. Visualizing published work. A blogging UI that can list posts and organize them by date and time published or category is incredibly useful when trying to reference older works. As is being able to quickly copy the permalink out of the admin (or right within the post editing UI in WordPress) and paste it into a link block. Octopress has no such mechanism and URLs can get really long. In fact, the permalink structure I’m using here is consistent with Octopress to maintain backward compatibility and I’m more or less stuck with it even though I’d rather it be much shorter.
  3. Version control over posts. This doesn’t matter to me as much anymore as it did in August. Markdown doesn’t version control very well anyway since lines are sometimes thousands of lines long. Also, with WordPress’s new drafting system, keeping track of changes in the post content is trivial and much more visual that it ever has been.
  4. Getting out. WordPress’s export/import functionality made switching to Octopress and it would have made switching back easy except that Octo has no similar feature. The upshot is that everything in Octo is straight HTML so importing wasn’t terribly difficult, but, manually re-entering the posts was time consuming and I’d rather not repeat it.

Paul Graham tweeted recently that static sites are “the fixies of the Internet”. I found that a compelling metaphor. To extrapolate it to my favorite bike company, WordPress is a complete Long Haul Trucker. Well built, tough and reliable enough to last you a long time. Octopress is the Cross-Check frame. It looks like it can do a lot but it’s unclear whether it’s a fixie, for touring, commuting, or something else entirely. The DIY aspects have a lot of advantages but also puts a lot of pressure on the user to decide what to do with it. Octopress clearly has a lot of advantages. But at the end of the day all I really want is to sit down and write a blog.

How can I use PHP Namespaces in WordPress Plugins

PHP has long had a problem of naming collisions. Because older versions of PHP had no way of declaring methods outside the global space, developers came up with several different ways of preventing and checking for namespace collisions, none of which treated the underlying condition. These many and varied solutions begged for a unifying standard as they made things like autoloading and package management increasingly difficult. PHP 5.3 introduced a feature called ‘namespacing’ to solve this problem and WordPress developers should begin adopting. With proper namespacing, WordPress plugin and themes will become clearer, more stable, and more portable.
<!–more–>

Prior to PHP 5, if you tried to name a method or class foo it might conflict with another similarly nammed method elsewhere in the system. Developers came to terms with this by ‘namespacing’ methods with a prefix. With this standard, foo became my_foo or gb_foo where the my_ or gb_ corresponded to vendor prefixes (gb, being my initials). It also led to wrapping every method in a conditional to check for namespace collisions:

if ( !function_exists(gb_foo) ) {
    function gb_foo( $bar ) {
        echo $bar;
    }
}

gb_foo('bar');

Look familiar? The problem with this should be easy to see. If that conditional returns false, my method `gb_foo` will never be fired and any time it’s called, that other `gb_foo` method will. Imagine if `gb_foo` was something like this:

function gb_foo($bar) {
    mysql_query('DROP TABLES *');
}

I think we can all agree that would be bad.

Namespacing is a concept familiar to many other programming languages that isolates your application from others in a standardized way. The global space should be reserved for only those things that should be available at all times. There is typically a character or pair of characters which globally signifies a namespace separator. In PHP it’s the backslash .

If properly namespaced, you can name your method foo() without any possibility of your method conflicting with anything else (unless you declare it twice in the namespace).

Namespacing also alleviates your need to wrap your methods in that conditional. A properly namespaced foo() method would look like this:

namespace gb;

function foo($bar) {
    echo $bar;
}

Let’s take a look at what’s going on here. On the first line we declare the namespace we want to use, in this case my initials gb. We can then declare classes and methods without worrying about stepping on any other methods. This is sort of like putting things in classes, but it’s even more safe. To call that ‘foo’ method, just type \gb\foo('baz'); which should output ‘baz’. You can also declare classes inside the namespace just like you would normally, the difference is that when these are called, the namespace must be too. There are a few different ways of approaching this:

Consider the application lives in a file called test.php and all our files are in the same directory.

// test.php
namespace gb;
class Bar {
    public static function foo($bar) {
        echo $bar;
    }
}

Example one: ‘Use’ the namespace, declared at the top of the second file.

require_once(DIR . '/test.php'); use \gb\Bar;

Bar::foo('baz');

Example two: Call the method with the namespace and class prefixed.

require_once(DIR . '/test.php');</p>

\gb\Bar::foo('baz');</p>

Example three: Instantiate the class as an object and declare the method from the object.

require_once(DIR . '/test.php');</p>

$object = new \gb\Bar();

$object->foo('baz');

They’re all very similar and should look familiar. Again, all the namespace does is add a layer of abstraction away from the global space in order to prevent collisions. Where it becomes particularly useful is in autoloading with tools like composer. With namespaces autoloaded, developers do not even need to require the files where those classes exist. They only need to know the namespaces. Example one, then, becomes:

use \gb\Bar;
Bar::foo('baz');

Pro tip: you can ‘use’ a namespace under another name. So if you have two classes Bar, you can redeclare them like this:

use \namespace\Bar as Bar;
use \gb\Bar as Baz;

Baz::foo('bar');

You can also stack namespaces to isolate your individual plugins from each other: namespace gb\myAwesomePlugin; and namespace gb\anotherAwesomePlugin serve as different namespaces for different plugins. It also keeps me safe from other ‘gb’s out there crowding my namespace.

Namespaces can also indicate where to find your application. With a fully namespaced plugin, you could even configure your WordPress install to use your plugin without ‘installing’ it. If you have composer doing that for you, you can autoload the plugin preconfigured the way you want it. WordPress is becoming an increasingly vibrant application development platform and namespacing will be key to it living in harmony with other PHP applications in complex systems.

Writing Unit Tests for WordPress

In my last post I wrote about two testing libraries for WordPress and briefly discussed the difference between integration tests and unit tests. I also mentioned a concept called test driven development (TDD) and breifly explained how it might help write better code from the start. This post will expand on that and show how to write a simple WordPress plugin from a test-first approach. Since we’re writing unit tests, we’re going to use WP-Mock to create a test double for us and we’ll use PHPunit for our test runner.

TDD starts with a problem you want to solve—the same problem your plugin wants to solve. In this case, let’s say we have a plugin that will add some metadata to a post with the title “Test”. Since that’s going to require us to mock some WordPress core functionality, make sure WP-Mock is configured in your working environment. We’ll start by writing a test that verifies the metadata was attached to the post.

In order to write unit tests we first need to extend the base test suite:

Class OurTestSuite extends PHPUnit_Framework_TestCase {

}

Now that we have a class, we can call any of PHPunit’s methods for testing including all of its assertions. Inside OurTestSuite is where we will write all our testing methods. We start with setUp and tearDown, commonly named methods that instantiate some conditions we will want for all our classes. We’ll want to make sure our setUp and tearDown methods clean up our test environment as well as any mocks we create out of WP_Mock. So we’ll declare:

public function setUp() {
         parent::setUp();
     }
     public function tearDown() {
         parent::tearDown();
     }

If we had other objects, variables, or settings we wanted available throughout the test suite, etc., we could declare those too. If you run the test now you’ll get some output, but no tests will run because we haven’t written any. Every test is a method within this class. Let’s write one that will always pass just to see PHPunit give us something.

...
     public function testOneExpectsOneAdded() {
         // Arrange
         $foo = 1;
         // Act
         $bar = $foo + 1;
         // Assert
         $this->assertEquals(2, $bar, 'Variable $bar does not equal two.');
    }

If you run PHPunit on that test, you should get a dot. Congratulations!

Now let’s write our test for our save_meta method. There are three basic sections to our test: Arrange, Act, and Assert. The first section is for all the bits our method needs for input. In our case, we’ll need the post ID for a post called “Test” and a key and value pair to save as metadata. Since the ID could be any integer on a given system, we can arrange our test with any integer we like. The next piece, the key-value pair, will be set in the method, but we’ll want to decide now what they’ll be.

The “Act” section is where we call the method. In this case, we’re going to call a method called save_meta_data out of the MetaMethods object. Finally, the “Assert” section is where we decide what the method should expect to see at the end. This section might be empty depending on whether the method under test returns an output or calls some other method. In our case, it’s the latter. The test passes if update_post_meta is called exactly once. Right now our test is looking something like this:

...
     public function testTestPostExpectsMetaDataSaved(){
         // Arrange
         $post_id = 42;
         // Act
         $methods = new MetaMethods();
         $methods->save_meta_data($post_id);
         // Assert
    }
...

Not a bad looking test, but we have some mocking to do. We already know we’ll need to mock update_post_meta(), but we’re also going to need get_post() as well. In both cases, we’re going to make PHPunit handle calls to those methods and return what we want back. We know what to expect if we call update_post_meta: if all is well with our WordPress install, we expect it would add new information to the post object. So we don’t need to verify that, all we really need to do is verify it’s being called exactly once. So let’s add our mocks to the “Arrange” section.

Fully mocking a function like get_post() uses the static method wpFunction() from WPMock. We can call it with: `\WPMock::wpFunciton(). We can also pass wpFunction some parameters like ‘times', for how many times we expect the mocked function to fire, and ‘parameters', and ‘return'. These help us create a fully function test double ofget_post`.

...
// Arrange
$post = \WP_Mock::wpFunction('get_post');
...

Finally, we need to address update_post_meta, but since we don’t particularly care what we get back from this method, we can instead ‘stub’ it. WP_Mock has a wrapper for wpFunction that make this easy, it’s called wpPassthruFunction() and can take many of the same parameters, but fills in the return value for you. In our case, we want to know that update_post_meta fired once, so we can write something like:

...
// Arrange
\WP_Mock::wpPassthruFunction('update_post_meta', array('times' => 1));
...

Now, if we run phpunit, we get a dot and an F, or maybe an E, since we haven’t written any code yet. Now we can write the actual code with the following workflow:

  1. Write some code
  2. Run the test
  3. Modify the test and code as necessary
  4. Repeat 2-3 until the test passes

A full example of our test is below:

Class OurTestSuite extends PHPUnit_Framework_TestCase {
     public function setUp() {
         parent::setUp();
     }
     public function tearDown() {
         parent::tearDown();
     }
     public function testOneExpectsOneAdded() {
         // Arrange
         $foo = 1;
         // Act
         $bar = $foo + 1;
         // Assert
         $this->assertEquals($bar, 2, 'Variable $bar does not equal two.');
    }

    public function testTestPostExpectsMetaDataSaved(){
        // Arrange
        $post_id = 42;
        $post = \WP_Mock::wpFunction('get_post');
        \WP_Mock::wpPassthruFunction('update_post_meta', array('times' => 1));
        // Act
        $methods = new MetaMethods();
        $methods->save_meta_data($post_id);

        // Assert
    }
}