How We Unit Test WP Migrate DB Pro

type-set

When you have a professional grade WordPress plugin such as WP Migrate DB Pro whose core functionality requires communication between two WordPress installations, how on Earth do you set up unit tests that don’t rely on a single “remote” site that every team member needs exclusive access to when they run their tests? Well, I’m glad you asked…

Up until recently, like many others, we used a straight clone of the install-wp-tests.sh script that you can find in WP-CLI to set up the skelton WordPress install and WordPress unit test frameworks for use with PHPUnit. We’d manually run install-wp-tests.sh, and then run phpunit. To test the functionality that depended on communicating with a remote install of WordPress, we had a remote install of WordPress set up on a server that the unit tests would communicate with and a custom plugin that would reset the database before each test.

This worked reasonably well while there was only one full-time developer using the unit tests. He’d occasionally run the unit tests, commit and push his work to GitHubTravis CI would then pick up the new changes and run the unit tests against various versions of PHP and WordPress (16 combinations). Occasionally he’d find that the builds started failing only to discover that the remote had got corrupted by two builds hitting it with unit tests at the same time. We fixed this by making Travis CI only run one build at a time, not ideal.

Then another couple of handsome developers came on board and started hitting the unit tests every now and then, sometimes quite often in fact. The poor old remote simply could not cope. We had ever increasing instances of the remote getting corrupted by database resets halfway through someone else’s unit test run and very often during a Travis CI build. And when we had more than one version of WP Migrate DB Pro in development we’d have issues with the remote having the wrong version of the plugin for tests being run which required manually updating the plugin on the remote.

Something had to be done. We were on a mission to increase our unit test coverage, especially as we had some important refactoring planned. To properly test plugin functionality that communicates with a remote site, we couldn’t continue with the system we had in place.

We needed the ability to set up both the local and remote installs of WordPress within a single run of the unit tests so that each developer and Travis CI had their own clean installs that no one else could interfere with.

To accomplish this we now have a script called run-unittests.sh that does a whole bunch of stuff for us to set up the clean environment and run the tests. Here’s some of the highlights:

  1. Checks that all required programs are available, e.g. mysqladmin, composer, npm, grunt, compass and curl.
  2. Validates the arguments.
  3. Installs the required npm packages.
  4. Builds the plugin using a fetched version of our plugin-build script.
  5. Uses composer to install PHPUnit.
  6. Runs a modified version of install-wp-tests.sh to set up the “local” WordPress install with the unit test framework.
  7. Creates a new database for the “remote”.
  8. Uses WP-CLI to download and set up a clean install of WordPress for the remote.
  9. Uses WP-CLI to install the WP Migrate DB Pro plugin we built on the remote.
  10. Uses WP-CLI to set a couple of required options on the remote.
  11. Finally, runs the unit tests!

It works pretty well, and means that as long as a developer has a local MySQL database server and web server set up (required if you’re developing a WordPress database migration plugin) and can create a local web address and document root for the unit tests to use for the “remote”, then the unit tests can test a good chunk of the AJAX functionality without clashing with other developers.

The usage message for our run-unittests.sh is:

Usage: run-unittests.sh -d testdb_name -r remotedb_name [ -u dbuser ] [ -p dbpassword ] [ -h dbhost ] [ -P dbport ] [ -x dbprefix ] [ -D (drop-db) ] [ -U remote_url ] [ -F remote_path ]

When I want to run the unit tests against my MAMP Pro setup, I use:

tests/bin/run-unittests.sh -d wordpress_test -r wpmdb_unittest -u root -p <DBPASSWORD> -h localhost -P 8889 -D -U http://wpmdb-unittest:8888

Although admittedly that’s actually in a little script so that I don’t have to remember or type that whole thing out.

We’ve made a couple of modifications to install-wp-tests.sh such as enabling dropping of a database before setting up a new clean one, using curl rather than wget (not everyone had wget installed by default), simplifying of the archive name we get for the various WordPress versions we test against and caching the downloaded files to reduce downloads.

An important part of our development process is our usage of Travis CI to run the unit tests against various versions of PHP (5.3 – 5.6), WordPress (3.9.x – latest) and single / multisite installs. To get our new self contained remote web server setup working on Travis CI, we had to add a few things to the before_script section of our .travis.yml file:

  1. Update the apt-get cache.
  2. Install apache2 and the fastcgi mod.
  3. Enable php-fpm.
  4. Configure an Apache virtual host.
  5. Bring up Apache.
  6. Install npm and the grunt-cli package.
  7. Install ruby and the compass gem.

This gets the Travis CI environment ready to run our run-unittests.sh script.

I hope you have enjoyed a little peek into how we have set up our unit tests to enable testing AJAX calls between two installs of WordPress.

About the Author

Ian Jones

Ian is always developing software, usually with PHP and JavaScript, loves wrangling SQL to squeeze out as much performance as possible, but also enjoys tinkering with and learning new concepts from new languages.

  • Casey Driscoll

    This is the first relevant and interesting wp post I’ve read in a long time. Thanks!

    • Thanks Casey, high praise indeed!

  • Thanks for sharing your tips and tricks on Unit Testing. Glad to know the WP Migrate DB Pro plugin is tested thoroughly. I love the plugin and we use it quite a bit.