Running WordPress PHPUnit Tests With Docker
Forest Hoffman Apr 11 '17
This is a repost of the original on my site.
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
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
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
Copy-pasted from my
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):
$ . ~/.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!