Okay, let’s install some tools. First a note about screen shots. I’ve taken the plugin file and readme file from the TruUcde project and put them in an empty folder labelled truucde-blog
. It’s sort of like in those cooking shows where a raw turkey goes in oven 1, we break for commercial, and a finished turkey comes out of oven 2. Well, sort of, but in reverse. Sort of.
Okay, this is a screenshot from inside PHPStorm, ignore the button bar. We can see though that this plugin directory sits inside plugins
, inside wp-content
, which is inside a local WordPress installation. Also ignore the .idea
folder, that is created by PHPStorm to store its own project settings.
What we’ll do in this post is first get PHP Code sniffer installed along with coding standards. These are things I install at the beginning of each coding project. They are useful to check code as you go, especially in an IDE as it will flag things for you. Once this stuff is in then we’ll get our unit testing items installed: PHPUnit and WPMock.
Oh, I forgot something
I’m going to slip an extra tool in on you here. I know I could go back and edit the tools articles, but this one isn’t specifically testing or code-quality related, but it is close to the first step of any project. Git. https://git-scm.com/. It is this tool that feeds github, bitbucket and other git repositories.
Git is a tool for saving code and code changes. It is referred to as version control software. My analogy is that it is a combination of save as and undo on steroids. If you don’t have Git installed (it is installed globally on your computer), go to the link above and the download section to get it.
What we are going to then is:
$ git init
You should get output that looks roughly like this:
I have a custom prompt, yours may be a simple $
like above. For each command we type at the command line we get a response, here it tells use that our git repo has been initialized. I’m not going to go too far into git, there is an excellent primer here: https://www.robinwieruch.de/git-essential-commands. I may from time to time indicate when it is a good time to commit (save) our changes.
Composer
Okay, let’s get composer installed and initialize our project. Okay, follow the installation instructors for your system here: https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos. As I indicated earlier, I install Composer globally. So for the Mac I did the following using the Manual Download:
wget https://getcomposer.org/download/1.10.7/composer.phar
mv composer.phar /usr/local/bin/composer
A couple of notes, don’t use the alpha version, there is enough going on already. The directory /usr/local/bin
is a directory on my path, so I can now run composer from anywhere via the command line.
To test your install, run the follow command:
composer --version
The second part, the --version
can be thought of as a subcommand of composer. We just want it to tell use the version number. If it does, we’re golden. If it is not installed correctly or can’t be found we’ll get an error instead.
The next step is to, from inside our project directory, run
composer init
This will ask you some questions about your project. If you are just noodling around you can leave them blank. Once it is done it will create a composer.json
file in your project folder.
I’m going to make a couple of notes on these questions. You can refer to https://getcomposer.org/doc/04-schema.md for a complete description of the composer.json
file.
I chose the GPL 2+ license because that is what WordPress is licensed as and its license requires addons to be similarly licensed. I answered no to both of the dependency questions because I want to install the dependencies individually.
There are two types of dependencies in PHP projects: regular dependencies and development dependencies. Regular dependencies are those packages installed with composer that need to be shipped with the final product in order for it to run.
In our case, the things we are installing will only be used during development, so we will install them as dev (require-dev) dependencies.
The final question was if we wanted the vendor directory added to the .gitignore
file. Here’s the breakdown, packages are specified in the composer.json
file, name and version. They are downloaded and stored in the vendor directory. When we are saving and moving our project via git there is no reason to move the actual packages with it. As long as users have our composer.json
file they can run composer install to download and install the packages.
Our starting composer.json file now looks like this:
{
"name": "twelch/truucde-blog",
"description": "WordPress plugin for Super and Site Admins to add users without white/black list restrictions.",
"type": "wordpress-plugin",
"license": "GPL 2.0+",
"authors": [
{
"name": "Troy Welch",
"email": "twelch@tru.ca"
}
],
"require": {}
}
I’ll just note a couple of things here. This is a json file and json files are super picky about spaces, brackets, etc. In general if you can let something like composer handle them it saves you some grief.
Also note that we have a require
area and will soon have a require-dev
area which is where our packages will be stored. Also the vendor
directory will be added as soon as we install something.
The other thing that happened is that we have a .gitignore
file that only has one line in it: /vendor/
which tells git to ignore this directory. I’m going to add the PHPStorm directory .idea
to it as well so that just our plugin stuff goes into git.
Okay, let’s install stuff.
Sniff, Sniff
Okay, we have a cluster of things to install related to the PHP Codesniffer.
- PHP codesniffer itself
- WP coding standards
- PHP compatibility standards
- PHP code sniffer composer installer.
The php code sniffer composer installer will configure our coding standards to work with code sniffer, so we’ll install that last. I can’t recall if the standards need the sniffer to be in first or not, but we’ll do it in that order so that we are okay if they do.
So, let’s have a quick look at the phpcs installation notes at https://github.com/squizlabs/PHP_CodeSniffer before we begin.
Okay, here’s a case where the developers think that phpcs should be installed globally. We are not going to do that, we’ll install it locally with the following command:
composer require --dev squizlabs/PHP_CodeSniffer
Note that I’m using the format developer/package to specify the package for the composer command. It is general the same as what is at the top of the github window except that github puts a space on each side of the slash. These spaces need to be removed if you are copy and pasting from github.
The output of this command should be something like:
So, it is telling us what has happened. It is using version 3.5 or higher but less than version 3.6. The first number in a version indicates a major version or breaking (in as it could break your code) update. So ^3.5 means that it will install versions above 3.5 that are bug fixes (in our case it actually installed 3.5.5 as you can see on the line beginning with ” – Installing”, but it won’t leave the 3.5 range. Also not that these aren’t decimal numbers, you could have something like 3.5.46. See https://getcomposer.org/doc/articles/versions.md for a more complete discussion of version and version constrictions.
So, it also tells us that it has updated our composer file, let’s see:
{
"name": "twelch/truucde-blog",
"description": "WordPress plugin for Super and Site Admins to add users without white/black list restrictions.",
"type": "wordpress-plugin",
"license": "GPL 2.0+",
"authors": [
{
"name": "Troy Welch",
"email": "twelch@tru.ca"
}
],
"require": {},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5"
}
}
Sure enough, there’s the addition of the require-dev
section and our first item. Our command output also tells us that it wrote a lock file, composer.lock
. Where composer.json
offers a little leeway in the version that is downloaded, the lock file specified exactly the versions of what was installed. Also, the lock file will also include any further dependencies that the package needs.
Finally it tells us it generated autoload files. This is really beyond our scope here, but this is a composer feature that automatically loads files when requested by code.
Coding standards
We’ll start with the WordPress coding standards. Looking at the installation instructions is likely to be a bit confusing. https://github.com/WordPress/WordPress-Coding-Standards#installation They first use the composer create-project command, which we don’t need because we already have a project. Then in the Install WPCS as a dependency section they don’t actually list our command which will be similar to what we used with phpcs, perhaps they assume that people know the command already. Anyway it looks much like the one above:
composer require --dev wp-coding-standards/wpcs
I won’t repeat the output here, it is very similar to the output for phpcs above. Except that there is what is called a warning: wp-coding-standards/wpcs suggests installing dealerdirect/phpcodesniffer-composer-installer (^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.)
We are already planning to do this after we install one more set of standards. This set checks our code for outdated PHP. Again, the installation instructions are a bit confusing and complex. https://github.com/PHPCompatibility/PHPCompatibility. In my opinion they miss the easier route again.
composer require --dev phpcompatibility/phpcompatibility-wp
It’s output is again similar to the phpcs output above. It also has the warning suggesting the installation of the phpcodesniffer-composer-installer package which we will do next, and it also suggests another package which helps prevent the installation of package versions with known security problems which we’ll do after.
So, our familiar routine:
composer require --dev DealerDirect/phpcodesniffer-composer-installer
Again, the output is very similar to the phpcs output, but this time we have an additional line advising us that:
PHP CodeSniffer Config installed_paths set to ../../phpcompatibility/php-compatibility,../../phpcompatibility/phpcompatibility-paragonie,../../phpcompatibility/phpcompatibility-wp,../../wp-coding-standards/wpcs
This is just telling us that it tied our coding standards into phpcs for us. Let’s quickly pop in the security package, it seems like a good idea:
composer require --dev roave/security-advisories:dev-master
Okay. I don’t want to get bogged down in using sniffers, this is an article on testing. The best bet is to consult your IDE documentation on how to configure the IDE to use them automatically. Here is the link for PHPStorm: https://www.jetbrains.com/help/phpstorm/using-php-code-sniffer.html. And a similar one for MS Visual Studio Code: https://tommcfarlin.com/php-codesniffer-in-visual-studio-code/.
Okay, let’s take stock before continuing. Our composer.json is looking pretty impressive:
{
"name": "twelch/truucde-blog",
"description": "WordPress plugin for Super and Site Admins to add users without white/black list restrictions.",
"type": "wordpress-plugin",
"license": "GPL 2.0+",
"authors": [
{
"name": "Troy Welch",
"email": "twelch@tru.ca"
}
],
"require": {},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5",
"wp-coding-standards/wpcs": "^2.3",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
"roave/security-advisories": "dev-master"
}
}
And our vendor directory is filling out too:
We are definitely getting there. The next step is to get the stuff that we need for unit testing installed.
Installing the Unit Testing Packages
Right, so the above things I would install for every coding project, usually before I code. PHPUnit and WPMock install much the same as our other composer projects, with one small twist for PHPUnit.
First, have a look above at the install command for the security-advisories package. See at the end of it, it has a colon then dev-master. This is requiring a specific named version. We want to install PHPUnit version 7 because that is what the WordPress integration tests will need later in the series. Now in our case we don’t need a specific version, we need the best version 7 variation.
We do that as follows:
composer require --dev 'phpunit/phpunit ^7'
The single quote marks around phpunit/phpunit ^7
are necessary to prevent some command line shells from interpreting the ^7 as a separate command because of the space.
Let’s look at the output, woah, that’s a pile of stuff. The things we have installed so far have not had any dependencies of their own. PHPUnit has a bunch of dependencies.
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 28 installs, 0 updates, 0 removals
- Installing sebastian/version (2.0.1): Loading from cache
- Installing sebastian/resource-operations (2.0.1): Loading from cache
- Installing sebastian/recursion-context (3.0.0): Loading from cache
- Installing sebastian/object-reflector (1.1.1): Loading from cache
- Installing sebastian/object-enumerator (3.0.3): Loading from cache
- Installing sebastian/global-state (2.0.0): Loading from cache
- Installing sebastian/exporter (3.1.2): Loading from cache
- Installing sebastian/environment (4.2.3): Downloading (100%)
- Installing sebastian/diff (3.0.2): Loading from cache
- Installing sebastian/comparator (3.0.2): Loading from cache
- Installing phpunit/php-timer (2.1.2): Loading from cache
- Installing phpunit/php-text-template (1.2.1): Loading from cache
- Installing phpunit/php-file-iterator (2.0.2): Loading from cache
- Installing theseer/tokenizer (1.1.3): Loading from cache
- Installing sebastian/code-unit-reverse-lookup (1.0.1): Loading from cache
- Installing phpunit/php-token-stream (3.1.1): Loading from cache
- Installing phpunit/php-code-coverage (6.1.4): Loading from cache
- Installing doctrine/instantiator (1.3.1): Downloading (100%)
- Installing symfony/polyfill-ctype (v1.17.0): Loading from cache
- Installing webmozart/assert (1.9.0): Downloading (100%)
- Installing phpdocumentor/reflection-common (2.1.0): Loading from cache
- Installing phpdocumentor/type-resolver (1.1.0): Loading from cache
- Installing phpdocumentor/reflection-docblock (5.1.0): Loading from cache
- Installing phpspec/prophecy (v1.10.3): Loading from cache
- Installing phar-io/version (2.0.1): Loading from cache
- Installing phar-io/manifest (1.0.3): Loading from cache
- Installing myclabs/deep-copy (1.9.5): Loading from cache
- Installing phpunit/phpunit (7.5.20): Downloading (100%)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
Writing lock file
Generating autoload files
3 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Basically, each of these packages provides a set of functionality. Rather than include them all in the PHPUnit package, they are simply included and installed as dependencies. If you look at the composer.json file now, you’ll see something you might not expect.
{
"name": "twelch/truucde-blog",
"description": "WordPress plugin for Super and Site Admins to add users without white/black list restrictions.",
"type": "wordpress-plugin",
"license": "GPL 2.0+",
"authors": [
{
"name": "Troy Welch",
"email": "twelch@tru.ca"
}
],
"require": {},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5",
"wp-coding-standards/wpcs": "^2.3",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
"roave/security-advisories": "dev-master",
"phpunit/phpunit": "^7"
}
}
The composer.json is not listing all of these extra things. So where are they being kept track of? The composer.lock
file does this for us. It’s a handy arrangement, because we mostly leave the composer.lock
file alone and just refer to the composer.json
file.
Okay, let’s get WPMock in and that will be the set of stuff we need for unit testing. The installation command should be familiar to us by now:
composer require --dev 10up/wp_mock
Good, notice that it also had a few dependencies. Not as many as PHPUnit though.
I’m going to do one more thing here before we move on. Back at the beginning of this article we initiated our project as a Git repo. I’m going to do a commit at this point so that I have a snapshot in time of what everything in my project looks like so far. Remember that the vendor and .idea folders are ignored.
Okay, there are three steps I usually take when committing (saving) a project (or repo git will call it.) First, I like to use the git status
command to see what state my repo is in.
╰─ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
README.md
composer.json
composer.lock
truucde.php
nothing added to commit but untracked files present (use "git add" to track)
So it tells me a number of things, first I’m on branch master and I have no commits yet. I’m not going to discuss branching in this series. Then it shows me (after removing anything identified in the ignore file) which untracked or changed files I have in my local repo. So step 2 of this will be to add all of these files to what is called the staging area:
git add -A
Now let’s see what our status looks like:
╰─ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: README.md
new file: composer.json
new file: composer.lock
new file: truucde.php
Now we see that all of these are considered new files by git and are ready to be committed. In order to commit we will run a commit command and add a message which explains the commit. In general you want your commit messages to indicate why you did something rather than what you did. What you did can be seen in the code, but why you did it is more useful. So, here we go:
╰─ git commit -m "Installed packages for sniffing and unit testing"
[master (root-commit) cd28acc] Installed packages for sniffing and unit testing
5 files changed, 2504 insertions(+)
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 composer.json
create mode 100644 composer.lock
create mode 100644 truucde.php
Okay, so we see my command, the -m
indicates that what follows in double quotes is my commit message, and we see the output. 5 files have been changed with 2504 insertions. Insertions generally refer to lines of code. Now let’s have a look at our git status:
git status
On branch master
nothing to commit, working tree clean
Okay, all our unit testing stuff is in. In the next article we’ll test that our stuff is working. This is often called a sanity test because you test operation with something very simple before throwing your code at it. This lets you know that the thing worked before you started and anything going wrong after that point is something that you did, probably code errors.
There is also some directory setup and configuration that we’ll need to do with PHPUnit and WPMock in the next article as well. See you there.