Greg Boone

Tag: WordPress

Writing Unit Tests for WordPress

This post and others like it still get a strange amount of traffic. It’s worth noting the details here are out of date and I won’t be keeping it up. Use at your own risk!

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
    }
}

Why Unit Testing in WordPress Matters

Testing WordPress has become a favorite topic of mine lately: moving away from hitting refresh and toward something more holistic, reliable, and automatable. I’ve written before about a testing method called called browser testing, which verifies a webpage has some expected behavior. These kinds of tests are great but they’re not perfect. They require a lot o dependencies and that someone else would need to verify your code. There is a better way, one that doesn’t require any of those dependencies and verfies the code down to the exact lines you wrote—it can even be independent of WordPress. It’s called unit testing and it will make you a better developer.

Continue reading “Why Unit Testing in WordPress Matters”

How can I use Feature Switches in WordPress

While a colleague and I were discussing the rollout of a new feature to our public facing website, he asked me if it would be possible to “hide” the new content behind a toggle. Effectively, he was asking me to write a feature switch, a best practice of continuous integration that allows you to push some source code while hiding future features. WordPress has some of this idea built into it’s core: plugins, for example, can be activated and deactivated to turn things on and off. Within plugins and themes, options pages can be used to turn on different features. SEO plugins, for example, let users turn on and off different optimizaiton tools. Feature switches are a little different, and in our case leverage the power of Apache environment variables to show and hide different parts of our site.

Continue reading “How can I use Feature Switches in WordPress”

How to Maybe Flush WordPress’s Rewrite Rules

Custom post types and taxonomies are one of the most powerful tools to transform WordPress from a blogging platform to a full CMS. One of the most common problems beginning developers have when starting to use them is understanding how they work. It’s easy to think that calling register_post_type is all it takes only to discover that their new post type archives are not working. This likely leads to a long dive into first (hopefully) the code to see if something was written incorrectly and then to the WordPress support forums to figure out what the problem is. 99% percent of the time I wager it’s because the developer forgot to flush WordPress’s rewrite rules.

Continue reading “How to Maybe Flush WordPress’s Rewrite Rules”

How can I do Browser Testing With WordPress

Browser testing is a basic component of a concept called behavior driven development (BDD), and one that has helped me become a better WordPress developer in the last few months. The concept of BDD is simple: test and develop around your software’s expected behavior. I recently wrote about BDD for Excella’s company blog, and this post will go a bit more technical than that. The upshot of behavior testing is you can find problems with both your code and your requirements. Before we get into that, a bit of background on the tools.

Continue reading “How can I do Browser Testing With WordPress”

A week into Octopress

About a week ago I successfully migrated some of my posts from harmsboone.org to this blog, I also wrote a post about some things I learned about git that week. WordPress is great. I wouldn’t recommend it (and I almost always do) if it weren’t. For someone who wants to spin up a blog and maybe some day more in a pinch, WordPress is the go-to platform. In fact, the rest of harmsboone.org still runs it. Earlier this year, though, Danielle and I started talking about ditching the one-blog-for-both solution. When we were both living and teaching abroad sharing one blog made sense but now with the both of us starting different careers, we have different things to say.

We decided to keep HarmsBoone.org as an archive of the last four years and also create new blogs for the both of us. Since I was starting from scratch anyway, might as well strike out with something new.

Continue reading “A week into Octopress”