title: Creating a Custom PHPUnit Command for Docksal
date: 2018-05-06
excerpt:
How to write custom commands for Docksal, including one to easily run PHPUnit
tests in Drupal 8.
tags:
- docksal
- drupal
- drupal-8
- drupal-planet
- phpunit
- testing
---
This week I’ve started writing some custom commands for my Drupal projects that
use Docksal, including one to easily run PHPUnit tests in Drupal 8. This is the
process of how I created this command.
## What is Docksal?
Docksal is a local Docker-based development environment for Drupal projects and
other frameworks and CMSes. It is our standard tool for local environments for
projects at [Microserve][0].
There was a [great talk][1] recently at Drupaldelphia about Docksal.
## Why write a custom command?
One of the things that Docksal offers (and is covered in the talk) is the
ability to add custom commands to the Docksal’s `fin` CLI, either globally or as
part of your project.
As an advocate of automated testing and TDD practitioner, I write a lot of tests
and run PHPUnit numerous times a day. I’ve also given [talks][6] and have
[written other posts][7] on this site relating to testing in Drupal.
There are a couple of ways to run PHPUnit with Docksal. The first is to use
`fin bash` to open a shell into the container, move into the docroot directory
if needed, and run the `phpunit` command.
```bash
fin bash
cd /var/www/docroot
../vendor/bin/phpunit -c core modules/custom
```
Alternatively, it can be run from the host machine using `fin exec`.
```
cd docroot
fin exec '../vendor/bin/phpunit -c core modules/custom'
```
Both of these options require multiple steps as we need to be in the `docroot`
directory where the Drupal code is located before the command can be run, and
both have quite long commands to run PHPUnit itself - some of which is repeated
every time.
By adding a custom command, I intend to:
1. Make it easier to get set up to run PHPUnit tests - i.e. setting up a
`phpunit.xml` file.
1. Make it easier to run the tests that we’d written by shortening the command
and making it so it can be run anywhere within our project.
I also hoped to make it project agnostic so that I could add it onto any project
and immediately run it.
## Creating the command
Each command is a file located within the `.docksal/commands` directory. The
filename is the name of the command (e.g. `phpunit`) with no file extension.
To create the file, run this from the same directory where your `.docksal`
directory is:
```bash
mkdir -p .docksal/commands
touch .docksal/commands/phpunit
```
This will create a new, empty `.docksal/commands/phpunit` file, and now the
`phpunit` command is now listed under "Custom commands" when we run `fin`.
![](/images/blog/docksal-phpunit-command/1.gif)
You can write commands with any interpreter. I’m going to use bash, so I’ll add
the shebang to the top of the file.
```bash
#!/usr/bin/env bash
```
With this in place, I can now run `fin phpunit`, though there is no output
displayed or actions performed as the rest of the file is empty.
## Adding a description and help text
Currently the description for our command when we run `fin` is the default "No
description" text. I’d like to add something more relevant, so I’ll start by
adding a new description.
fin interprets lines starting with `##` as documentation - the first of which it
uses as the description.
```bash
#!/usr/bin/env bash
## Run automated PHPUnit tests.
```
Now when I run it, I see the new description.
![](/images/blog/docksal-phpunit-command/2.gif)
Any additional lines are used as help text with running `fin help phpunit`. Here
I’ll add an example command to demonstrate how to run it as well as some more
in-depth text about what the command will do.
```bash
#!/usr/bin/env bash
## Run automated PHPUnit tests.
##
## Usage: fin phpunit <args>
##
## If a core/phpunit.xml file does not exist, copy one from elsewhere.
## Then run the tests.
```
Now when I run `fin help phpunit`, I see the new help text.
![](/images/blog/docksal-phpunit-command/3.gif)
## Adding some content
### Setting the target
As I want the commands to be run within Docksal’s "cli" container, I can specify
that with `exec_target`. If one isn’t specified, the commands are run locally on
the host machine.
```
#: exec_target = cli
```
### Available variables
These variables are provided by fin and are available to use within any custom
commands:
-`PROJECT_ROOT` - The absolute path to the nearest `.docksal` directory.
-`DOCROOT` - name of the docroot folder.
-`VIRTUAL_HOST` - the virtual host name for the project. Such as
`myproject.docksal`.
-`DOCKER_RUNNING` - (string) "true" or "false".
<divclass="note"markdown="1">
**Note:** If the `DOCROOT` variable is not defined within the cli container, ensure that it’s added to the environment variables in `.docksal/docksal.yml`. For example:
```
version: "2.1"
services:
cli:
environment:
- DOCROOT
```
</div>
### Running phpunit
When you run the `phpunit` command, there are number of options you can pass to
it such as `--filter`, `--testsuite` and `--group`, as well as the path to the
tests to execute, such as `modules/custom`.
I wanted to still be able to do this by running `fin phpunit <args>` so the
commands can be customised when executed. However, as the first half of the
command (`../vendor/bin/phpunit -c core`) is consistent, I can wrap that within
my custom command and not need to type it every time.
By using `"$@"` I can capture any additional arguments, such as the test
directory path, and append them to the command to execute.
I’m using `$PROJECT_ROOT` to prefix the command with the absolute path to
`phpunit` so that I don’t need to be in that directory when I run the custom
command, and `$DOCROOT` to always enter the sub-directory where Drupal is
located. In this case, it’s "docroot" though I also use "web" and I’ve seen
various others used.
```bash
DOCROOT_PATH="${PROJECT_ROOT}/${DOCROOT}"
DRUPAL_CORE_PATH="${DOCROOT_PATH}/core"
# If there is no phpunit.xml file, copy one from elsewhere.
It’s currently available as a [GitHub Gist][2], though I’m planning on moving it
into a public GitHub repository either on my personal account or the [Microserve
organisation][3], for people to either use as examples or to download and use
directly.
I’ve also started to add other commands to projects such as `config-export` to
standardise the way to export configuration from Drupal 8, run Drupal 7 tests
with SimpleTest, and compile front-end assets like CSS within custom themes.
I think it’s a great way to shorten existing commands, or to group multiple
commands into one like in this case, and I can see a lot of other potential uses
for it during local development and continuous integration. Also being able to
run one command like `fin init` and have it set up everything for your project
is very convenient and a big time saver!
<divclass="note"markdown="1">
Since writing this post, I’ve had a [pull request][8] accepted for this command to be added as a [Docksal add-on][9]. This means that the command can be added to any Docksal project by running `fin addon install phpunit`. It will be installed into the `.docksal/addons/phpunit` directory, and displayed under "Addons" rather than "Custom commands" when you run `fin`.