Running WordPress PHPUnit Tests With Docker

I recently moved my web development workspace from MAMP to LAMP with Docker. The transition was difficult, due to issues with Ruby and RVM on my host machine. Now that it is working, all is well!

When I started tinkering with Docker, my goal was just to see if I could replicate my WordPress development environment. After I did that, I improved it a bit. Now, i’ve suitably compartmentalized each project. Each WordPress project has its own WordPress installation, MySQL server, error logs, plugin and theme directories.

The only thing missing was being able to run unit tests!

I vaguely remember having a frustrating time getting the Core WordPress tests to run with PHPUnit, the last time I set it up. This time was equally frustrating. I found an unfortunate lack of up-to-date and complete resources to deal with this process, so I made this article to fill the gap! I hope this helps someone avoid the same frustrations I experienced. If not, eh, at least I have the process documented for my future self.

The error that I kept receiving upon running $ phpunit was some HTML content, and a load of errors. The essence of it being, <h1>Error establishing a database connection</h1>.

Rather than including a testing database in each WordPress project, I created a MySQL container to be shared by all of my projects. I also configured the container to restart whenever the Docker daemon starts, so that it will always be available.

Setting up WordPress Core Tests

In the same directory as my other WordPress projects (which contain individual Dockerfile and docker-compose.yml files), I created a wordpress-develop directory. To this new directory, I cloned the WordPress Core Tests repository.

$ svn co https://develop.svn.wordpress.org/trunk/ wordpress-develop

I then prepared the wp-tests-config.php file within wordpress-develop/. I found where the various global variables were being set at the bottom of the file, and updated them as follows:

define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'root' );
define( 'DB_PASSWORD', 'root' );
define( 'DB_HOST', '127.0.0.1:914' );

# ...

define( 'WP_TESTS_DOMAIN', 'localhost' );
define( 'WP_TESTS_TITLE', 'Testing' );

This sets the database name to wordpress, the username and password to root, and domain to localhost. The issue that I ran into earlier was that the database host didn’t recognize the value 'localhost:914' as valid. This resulted in failed attemps to connect to the database, when I ran phpunit from within wordpress-develop/. By exchanging localhost for a raw IP, 127.0.0.1 PHPUnit was able to connect. I actually found this fix recommended on a related Stack Exchange comment.

I chose the 914 port, because these UNIX port tables indicate that the 914-986 range is officially unassigned. I needed a port that wouldn’t get in the way, and 914 wasn’t being used on my machine. I ran $ curl http://127.0.0.1:914 just to check.

Creating the MySQL daemon

Using a combination of docker run and the restart option, it is possible to create a MySQL container that will startup whenever the Docker daemon does. That includes when the host machine restarts.

$ docker run --name wptest-mysql --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --env MYSQL_USER=root --env MYSQL_PASSWORD=root -p 0.0.0.0:914:3306 --restart=always -d mysql:5.7

The above command includes all of the data that we provided in the wp-tests-config.php file, and a bit more. The name option determines the name of the container; for easy identification I chose wptest-mysql, since wordpress-develop-mysql was a bit long. The env option is repeated several times, providing the container with the necessary environmental variables. The p option maps a port on the host machine to the container; so, 0.0.0.0:914 maps port 914 on the host to the port 3306 on the container. The restart option with the always value indicates that Docker should attempt to restart the container no matter how it exited. The d option indicates the image off of which to base the container. I used MySQL version 5.7.

At this point, running $ docker ps -a should reveal the new wptest-mysql container running with local port 914.

$ docker ps -a
24d9f30b5286        mysql:5.7           "docker-entrypoint..."   46 hours ago        Up 46 hours         0.0.0.0:914->3306/tcp   wptest-mysql

If it appears that the container is running properly, navigate to your wordpress-develop directory and run $ phpunit. If everything is running as it should, you’ll see the WordPress test install begin to run, followed by the tests.

Running WordPress tests elsewhere

Running the WordPress Core Tests is fantastic, but I really needed to run my own tests. In order to do this I took the path to my WordPress tests and assigned it to the WP_TESTS_DIR environmental variable in my ~/.bash_profile. This environmental variable is relied on by the project-based tests/bootstrap.php files, which require the necessary WordPress files from the wordpress-develop directory.

Copy-pasted from my ~/.bash_profile:

export DOCKER="$HOME/Documents/Programming/docker"
export WP_DEVELOP_DIR="$DOCKER/wordpress/wordpress-develop"
export WP_TESTS_DIR="$WP_DEVELOP_DIR/tests/phpunit"

If you have no need for the other environment variables, you can stick it all together like so (obviously, use the correct path on your machine):

export WP_TESTS_DIR="$HOME/Documents/Programming/docker/wordpress/wordpress-develop/tests/phpunit"

Run $ . ~/.bash_profile to activate the changes. After that, running $ phpunit next to a project’s respective phpunit.xml file and tests directory should run the local tests, as expected.

That’s it, woot!