This article is a part of a series on writing object-oriented PHP for WordPress development. So far, we’ve spent two articles on writing the code and now we will test the code and systems. It takes an enormous amount of tooling to write code and back in my day I walked uphill both ways, in two feet of snow, to write HTML, using HTML instead of writing it in Babel and transferring it to HTML.
Yes, it’s a lot, but that’s why we have scaffolding tools, and we’re going to get into some of those in this article.
Object-oriented programming (OOP) is complex. The point of this series is to show why creating abstract systems to do things is sometimes better than writing a system to do one thing. When that is true, OOP is worth the additional complexity. One key benefit of OOP is that testable code, tends to be better code.
Since OOP code is highly testable, it’s reasonable to adopt a workflow where all code is automatically tested. Passing tests becomes a requirement for merging pull requests. Github and GitLab can enforce this rule on pull requests. This is an important component of the workflow if you want to adopt test-driven design (TDD,) which this series will switch to soon.
In this article, I’ll be showing you how to use Github and Travis CI to automatically run the tests that I showed you how to write in the previous articles.
Git Flow And Testing
The Git Flow Workflow is a very common choice for collaborative development using Git. When using this workflow, no one ever commits directly to the branch currently being developed on. Instead, all work happens in branches, and a pull request on Github is used to review and then commit the changes back to the main branch.
For example, if you were tasked with implementing features specified in issue 42 in a branch called “develop”. In this case, you would pull the remote git branch develop. Then create a local branch off of develop. That branch would be called feature/42, since it is introducing a feature from issue 42, and then push that feature back to Github. A pull request to merge feature/42.
Setting Up Testing Automation With Travis CI
Travis CI is a free service that integrates with Github pretty seamlessly. Once you’ve signed up for a Travis CI account, you can connect your personal repos and organization repos. Then in the Travis CI profile for your personal account or organization, search for the repository you want to enable Travis for and activate it.
This takes you to the Travis page for your repo. Go to settings and set Travis to run on all pull requests.
Keep that screen open. We’ll need it once we are ready to use Travis, but that requires a Travis configuration file — .travis.yml.
This is the configuration file for the Travis build environment, which is running inside of a Docker image. You can use this file to configure that environment — for example we’ll tell it we want PHP available. You can use this file to run scripts in that environment, for example the bash and composer scripts I showed how to create in previous articles in this series.
Let’s start with a basic Travis file that just runs our unit tests.
# Do not give sudo access sudo: false # Use the PHP environment language: php # Don't send notifications via email, that's annoying notifications: email: on_success: never on_failure: never # Trigger only on master -- we'll add Github pull requests in settings branches: only: - master # Cache composer dependencies cache: directories: - vendor - $HOME/.composer/cache # Build these combinations of PHP and WordPress Versions matrix: include: - php: 7.2 env: WP_VERSION=latest - php: 7.1 env: WP_VERSION=latest - php: 7.2 env: WP_VERSION=trunk # Setup environment before_script: # Export composer - export PATH="$HOME/.composer/vendor/bin:$PATH" # Install plugin with composer - composer install --no-progress # Run tests script: # Run just unit tests - composer unit-tests
Travis Life Cycle Events
This file has inline explanations. I want to highlight a few parts that are very important concepts. First, the matrix. Because this matrix includes three combinations of PHP and WordPress versions, Travis will perform three builds each time. Each run will use the PHP version specified and will have a different value for the environment variable WP_VERSION. The bash scripts that I created — based on Gutenberg — all set the WordPress version they are using the environment variable WP_VERSION. It’s a convention that we should stick to.
Next look at “below_script”. This is a lifecycle event that Travis exposes. This event runs before the script event, which is normally where the test script runs. At this stage our travis file setups up composer and then uses it to install the plugin’s dependencies. This has to happen before the tests are run or they will fail for the wrong reason — bad install, not bad code.
Then we have the “script” event. By default, in a PHP project, Travis will execute the command “phpunit” here. We want to run a slightly different command. More specifically the command “composer unit-tests”. That’s the Composer script that encapsulates running unit tests.
In the next series of this article, we’ll use Travis lifecycle events to run code sniffs and lints before the tests. Then, with one build, we’ll create a code coverage report, that can tell us what percentage of our code is covered by our tests.
Testing The Travis Configuration
Now commit this file and push it to Github, in the master branch. Then go back to the Travis settings screen and from the “More Options” menu, use the “Trigger Build” to trigger a build. That should cause the build process to run and once it’s done, you’ll see the status.
If you had a resolvable set of dependencies that are all passing tests, you should see each three build passed. You probably didn’t. Travis is a much less forgiving environment than most of us use for local development. That’s a good thing. If everything works in Travis, then it likely works elsewhere. Read your error logs and work through each one until you’ve got passing builds.
The complete configuration with Docker I’m about to show you how to build, when I set it up for the example plugin took me twelve tries to get it right. I’m borrowing liberally from Gutenberg and I’ve done this before. If this is your first time setting up Travis or any CI system at all, be patient, this is not the easiest thing in the world to do. But once it’s setup it should just work.
Using Docker To Run WordPress Integration Tests On Travis
Right now, we’re just running the unit tests. That’s a simple first step, but we also have a suite of integration tests to run as well. Because the unit tests are written in a way that does not require dependencies, we can just run those tests using the system PHP. In this case, the Docker environment Travis provisioned for us.
The integration tests require MySQL and WordPress running on localhost. We solved that problem for local development with a simple Docker environment created using Docker Compose. We can enable Docker and Docker Compose inside of the Travis environment by adding a “services” section to our .travis.yml. Once we’ve done that, our existing docker-compose.yml file and composer scripts are all we need.
In the “script” section, after running the unit tests, I added two commands. First, the preexisting composer script to install the docker environment, which provisions the test suite. Second, the command to run the integration tests.
Here is the new Travis file:
# Give sudo to environment sudo: required # Make Docker available inside the container services: - docker # Use the PHP environment language: php # Don't send notifications via email, that's annoying notifications: email: on_success: never on_failure: never # Trigger only on master -- we'll add Github pull requests in settings branches: only: - master # Cache composer dependencies cache: directories: - vendor - $HOME/.composer/cache # Build these combinations of PHP and WordPress Versions matrix: include: - php: 7.2 env: WP_VERSION=latest - php: 7.1 env: WP_VERSION=latest - php: 7.2 env: WP_VERSION=trunk # Setup environment before_script: # Export composer - export PATH="$HOME/.composer/vendor/bin:$PATH" # Install plugin with composer - composer install --no-progress # Run tests script: # Run just unit tests first -- if they fail we never spend the time building the environment for integration tests - composer unit-tests # Install full test environment using composer script - composer wp-install # Run integration tests - composer wp-tests # IF tests passed run coverage and sniffs after_sucess: # Run coverage - vendor/bin/phpunit --coverage-clover=coverage.xml # Report to codecov - bash <(curl -s https://codecov.io/bash) CODECOV_KEY
Installing the testing environment is one of the slowest parts of the build process. That’s why I am running unit tests first. That’s the fastest way to fail the build. If the code has a fatal error, for example, one caused by a bad git merge, the unit tests are not going to complete and the failure is reported without having to install the larger test suite. Since every build is actually multiple builds, total build time can increase significantly over time.
Continuing With Continuous Integration
Travis CI is one example of a continuous integration tool. I like the simplicity of Travis. Gitlab CI and CircleCI are alternatives that are a bit more complex. Those services are worth checking out.
Also keep in mind that, CI is the first half of CI/CD — continuous integration and continuous deployment. The CD part, is the process of automatically deploying changes to servers. If you’re implementing continuous integration for a WordPress site or WordPress-powered app, you can use a CI/CD service to update your site for you.
Once your automated tests for your site reach a point that you can trust that, if they pass, you trust the code, then you might as well have the code be deployed to your live site, or even better a QA site automatically. That’s all tedious work to do manually. These tests create
For plugin development, the deployment part involves building a release ZIP file and then using that to create an SVN commit on WordPress.org and/ or uploading the ZIP to your eCommerce site or marketplace. Travis has SVN installed and supports encrypted environment variables, so if you had a script to create a production build of your plugin, like this one in Gutenberg, you could create a build a commit it as a tag on WordPress.org or rysnc it to another location.