Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Setup PHPUnit for use in the Local by Flywheel app
#!/usr/bin/env bash
# ===============================================================================
# Script to install PHPUnit in the Local by Flywheel Mac app
# These packages are installed
#
# PHPUnit, curl wget, rsync, git, subversion and composer.
#
# WordPress is installed in the `/tmp/wordpress` directory for use by PHPUnit.
# The WordPress test suite is installed in the `/tmp/wordpress-tests-lib` directory.
#
# The WordPress and WP Test Suite paths are added to the ~/.bashrc file as environment
# variables $WP_CORE_DIR and $WP_TESTS_DIR.
#
# That way plugins can make use of them for unit testing. Plugins that have their
# tests scaffolded by WP-CLI also makes use of them. VVV also adds these enviroment
# variables to the ~/.bashrc file by default.
#
# You only have to run this script once. PHPUnit (and the other packages) are
# still available next time you ssh into your site.
#
# To update WordPress and the WP Test Suite re-run this script.
# Use options to install specific versions for PHPUnit, WordPress or the WP_UnitTestCase.
#
# Note: This script doesn't install the packages globally in the Local by Flywheel app
# Packages are only installed for the site where you've run this script.
# ===============================================================================
# ===============================================================================
# Instructions
#
# 1 - Download this file (setup-phpunit.sh) inside your site's /app folder
# curl -o setup-phpunit.sh https://gist.githubusercontent.com/keesiemeijer/a888f3d9609478b310c2d952644891ba/raw/
#
# 2 - Right click your site in the Local App and click Open Site SSH
# A new terminal window will open
#
# 3 - Go to your site's /app folder:
# cd /app
#
# 4 - Run this script
# bash setup-phpunit.sh
#
# 5 - Reload the .bashrc file
# source ~/.bashrc
#
# 6 - Check if PHPUnit is installed
# phpunit --version
#
# ===============================================================================
# ===============================================================================
# Options
#
# Without options this script installs/updates PHPUnit, WordPress and the WP test suite.
#
# Install a specific PHPUnit version with the --phpunit-version option.
#
# bash setup-phpunit.sh --phpunit-version=7
#
# Install a specific WordPress version with the --wp-version option. This option
# accepts a version number, 'latest', 'trunk' or 'nightly'. Default 'latest'
#
# bash setup-phpunit.sh --wp-version=5.0
#
# Install a specific WordPress Test Suite with the --wp-ts-version option. This option
# accepts a version number, 'latest', 'trunk' or 'nightly'. Default 'latest'
#
# bash setup-phpunit.sh --wp-ts-version=trunk
#
# Update all packages (wget, curl etc) installed by this script with the --update-packages option.
#
# bash setup-phpunit.sh --update-packages
#
# Use the --help or -? option to see more information about this script.
#
# bash setup-phpunit.sh --help
#
# ===============================================================================
# ===============================================================================
# Default PHPUnit version
#
# The default installed PHPUnit version is similar to versions used in
# WordPress travis.yaml file in trunk.
#
# See https://core.trac.wordpress.org/browser/trunk/.travis.yml#L64
#
# PHPUnit version 7 is installed for PHP version 7.1 and above
# PHPUnit version 5 is installed for PHP version 7.0
# PHPUnit version 4 for all other PHP versions
#
# See ticket https://core.trac.wordpress.org/ticket/39822
# See ticket https://core.trac.wordpress.org/ticket/43218
#
# Run the command with a version if you need to test with a specific PHPUnit version
#
# bash setup-phpunit.sh --phpunit-version=7
#
# This example will install the latest PHPUnit from version 7 (e.g. 7.5.3)
#
# Available PHPUnit versions can be found here.
# https://phar.phpunit.de
#
# PHPUnit versions compatible with PHP versions can be found here.
# https://phpunit.de/supported-versions.html
#
# ===============================================================================
# Strings used in error messages.
readonly QUIT="Stopping script..."
readonly CONNECTION="Make sure you're connected to the internet."
readonly RED='\033[0;31m' # Red color.
readonly RESET='\033[0m' # No color.
# Functions
function download() {
download=false
if wget --spider "$1" >/dev/null 2>&1; then
wget -q --show-progress -O "$2" "$1" && download=true
# Check if file exists.
if [[ -f "$2" && "$download" = true ]]; then
return 0
fi
fi
printf "${RED}WARNING${RESET} Could not download %s %s\n" "$1" "$CONNECTION"
return 1
}
function download_test_suite() {
local exit=0
if wget --spider "https://develop.svn.wordpress.org/$1/tests/phpunit/includes/" >/dev/null 2>&1; then
svn export --quiet --force "https://develop.svn.wordpress.org/$1/tests/phpunit/includes/" "/tmp/tmp-wordpress-tests-lib/includes/"
svn export --quiet --force "https://develop.svn.wordpress.org/$1/tests/phpunit/data/" "/tmp/tmp-wordpress-tests-lib/data/"
svn export --quiet --force "https://develop.svn.wordpress.org/$1/wp-tests-config-sample.php" "/tmp/tmp-wordpress-tests-lib/wp-tests-config.php"
for path in includes data wp-tests-config.php; do
# Check if path exists.
[[ ! -e "/tmp/tmp-wordpress-tests-lib/$path" ]] && exit=1
done
if [[ 0 = "$exit" ]]; then
return 0
fi
fi
printf "${RED}WARNING${RESET} Could not download %s Test Suite. %s\n" "$2" "$CONNECTION"
return 1
}
function packages_installed() {
for file in /usr/bin/wget /usr/bin/curl /usr/bin/svn /usr/bin/rsync /usr/local/bin/composer /usr/bin/git; do
# Check if executable file.
if ! [[ -f "$file" && -x "$file" ]]; then
return 1
fi
done
return 0
}
function clean_up_temp_files() {
# Clean up files added by this script.
[[ -d "/tmp/tmp-wordpress/" ]] && rm -rf "/tmp/tmp-wordpress/"
[[ -d "/tmp/tmp-wordpress-tests-lib/" ]] && rm -rf "/tmp/tmp-wordpress-tests-lib/"
[[ -f "/tmp/my.cnf" ]] && rm -f "/tmp/my.cnf"
}
function exit_script() {
clean_up_temp_files
exit 1
}
# Get arguments.
for arg in "$@"
do
if [[ "$arg" =~ ^- ]]; then
# Argument start with a dash.
case "$arg" in
--phpunit-version=*) PHPUNIT_VERSION=${arg#"--phpunit-version="};;
--wp-version=*) WP_VERSION=${arg#"--wp-version="};;
--wp-ts-version=*) WP_TS_VERSION=${arg#"--wp-ts-version="};;
--update-packages*) UPDATE_PACKAGES=true;;
-?|--help)
printf "Install PHPUnit in the Local by Flywheel Mac app\n\n"
printf "Usage:\n"
printf "\tbash setup-phpunit.sh [option...]\n\n"
printf "Example:\n"
printf "\tbash setup-phpunit.sh --phpunit-version=6 --wp-version=trunk\n\n"
printf "Options:\n"
printf -- "\t--phpunit-version PHPUnit version to install\n"
printf -- "\t--wp-version WordPress version to install\n"
printf -- "\t Accepts a version number, 'latest', 'trunk' or 'nightly'. Default 'latest'\n"
printf -- "\t--wp-ts-version WordPress Test Suite version to install\n"
printf -- "\t Accepts a version number, 'latest', 'trunk' or 'nightly'. Default --wp-version option\n"
printf -- "\t--update-packages Update all packages installed by this script\n"
printf -- "\t Updates curl wget, rsync, git, subversion and composer\n"
printf -- "\t-?|--help Display information about this script\n\n"
exit 0
;;
*)
printf "Unknown option: %s.\nUse \"bash setup-phpunit.sh --help\" to see all options\n%s\n" "$arg" "$QUIT_MSG"
exit_script
;;
esac
else
# Argument doesn't start with a dash.
printf "Unknown option: %s.\nUse \"bash setup-phpunit.sh --help\" to see all options\n%s\n" "$arg" "$QUIT_MSG"
exit_script
fi
done
INSTALL_PACKAGES=false
if ! packages_installed; then INSTALL_PACKAGES=true; fi
[[ -z "$UPDATE_PACKAGES" ]] && UPDATE_PACKAGES=false
if [[ "$INSTALL_PACKAGES" = true || "$UPDATE_PACKAGES" = true ]]; then
[[ "$INSTALL_PACKAGES" = true ]] && printf "Installing packages...\n" || printf "Updating packages...\n"
# Re-synchronize the package index files from their sources.
apt-get update -y
# Install packages.
apt-get install -y wget subversion curl git rsync
# Install composer.
if [[ -f "/usr/bin/curl" && ! -f "/usr/local/bin/composer" ]]; then
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer || exit
if [[ -f "$HOME/.bashrc" ]]; then
printf "Adding .composer/vendor/bin to the PATH\n"
echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> "$HOME/.bashrc"
fi
else
if [[ -f "/usr/local/bin/composer" ]]; then
printf "Updating composer...\n"
composer self-update || printf "${RED}WARNING${RESET} Could not update composer. %s\n" "$CONNECTION"
fi
fi
fi
# Re-check if all packages are installed.
if ! packages_installed; then
printf "${RED}ERROR${RESET} Missing packages. %s\n%s\n" "$CONNECTION" "$QUIT"
exit_script
fi
# Get the current PHP version.
PHP_VERSION=$(php -r "echo PHP_VERSION;")
# Get first three characters from version
readonly PHP_VERSION="${PHP_VERSION:0:3}"
# Set the PHPUnit version if needed.
if [[ -z "$PHPUNIT_VERSION" ]]; then
case "$PHP_VERSION" in
7.4|7.3|7.2|7.1)
PHPUNIT_VERSION=7
;;
7.0)
PHPUNIT_VERSION=5
;;
*)
PHPUNIT_VERSION=4
;;
esac
fi
readonly PHPUNIT_VERSION="$PHPUNIT_VERSION"
# Install PHPUnit.
printf "Installing PHPUnit %s... \n" "$PHPUNIT_VERSION"
if download "https://phar.phpunit.de/phpunit-$PHPUNIT_VERSION.phar" "phpunit-$PHPUNIT_VERSION.phar"; then
chmod +x "phpunit-$PHPUNIT_VERSION.phar"
mv "phpunit-$PHPUNIT_VERSION.phar" /usr/local/bin/phpunit
else
printf "%s\n" "$QUIT"
exit_script
fi
# Set WordPress environment variables.
if [[ -f "$HOME/.bashrc" ]]; then
# Get the variables.
source "$HOME/.bashrc"
if [[ -z "${WP_TESTS_DIR}" ]]; then
printf "Setting WP_TESTS_DIR environment variable\n"
echo 'export WP_TESTS_DIR=/tmp/wordpress-tests-lib' >> "$HOME/.bashrc"
fi
if [[ -z "${WP_CORE_DIR}" ]]; then
printf "Setting WP_CORE_DIR environment variable\n"
echo 'export WP_CORE_DIR=/tmp/wordpress' >> "$HOME/.bashrc"
fi
# Get the new variables.
source "$HOME/.bashrc"
fi
if [[ -z "$WP_CORE_DIR" || -z "$WP_TESTS_DIR" ]]; then
printf "${RED}ERROR${RESET} The WordPress directories for PHPUnit are not set\n%s\n" "$QUIT"
exit_script
fi
# Delete tmp files (if they exist).
clean_up_temp_files
# Create tmp directories.
mkdir "/tmp/tmp-wordpress/" || exit
mkdir "/tmp/tmp-wordpress-tests-lib/" || exit
# Create core and tests directories (if needed).
[[ -d "$WP_CORE_DIR" ]] || mkdir "$WP_CORE_DIR" || exit
[[ -d "$WP_TESTS_DIR" ]] || mkdir "$WP_TESTS_DIR" || exit
cd "$WP_CORE_DIR" || exit
# Set default WordPress version.
[[ -z "$WP_VERSION" ]] && WP_VERSION='latest'
# Get the latest WordPress version from API.
readonly WP_LATEST=$(wget -q -O - "http://api.wordpress.org/core/version-check/1.5/" | head -n 4 | tail -n 1);
if [[ 'latest' = "$WP_VERSION" ]]; then
WP_VERSION="$WP_LATEST"
if [[ -z "$WP_LATEST" ]]; then
printf "${RED}ERROR${RESET} Could not get latest WordPress version from api.wordpress.org. %s\n%s\n" "$CONNECTION" "$QUIT"
exit_script
fi
fi
# Set WordPress version.
readonly WP_VERSION="$WP_VERSION"
# Set default test suite version.
[[ -z "$WP_TS_VERSION" ]] && WP_TS_VERSION="$WP_VERSION"
# Install WordPress.
if [[ 'trunk' = "$WP_VERSION" ]]; then
printf "Installing WordPress trunk... \n"
svn export --quiet --force "https://develop.svn.wordpress.org/trunk/src/" "/tmp/tmp-wordpress/"
rsync -a --delete "/tmp/tmp-wordpress/" "$WP_CORE_DIR"
elif [[ 'nightly' = "$WP_VERSION" ]]; then
printf "Installing WordPress nightly... \n"
if download "https://wordpress.org/nightly-builds/wordpress-latest.zip" "/tmp/wordpress-latest.zip"; then
unzip -o -q "/tmp/wordpress-latest.zip" -d "/tmp/tmp-wordpress/"
rsync -a --delete "/tmp/tmp-wordpress/wordpress/" "$WP_CORE_DIR"
fi
else
printf "Installing WordPress %s... \n" "$WP_VERSION"
if download "https://wordpress.org/wordpress-$WP_VERSION.tar.gz" "/tmp/wordpress.tar.gz"; then
tar --strip-components=1 -zxmf "/tmp/wordpress.tar.gz" -C "/tmp/tmp-wordpress/"
rsync -a --delete "/tmp/tmp-wordpress/" "$WP_CORE_DIR"
fi
fi
if [[ 'trunk' = "$WP_TS_VERSION" || 'nightly' = "$WP_TS_VERSION" ]]; then
TS_ARCHIVE="trunk"
elif [[ $WP_TS_VERSION = 'latest' ]]; then
TS_ARCHIVE="tags/$WP_LATEST"
WP_TS_VERSION="$WP_LATEST"
else
TS_ARCHIVE="tags/$WP_TS_VERSION"
fi
# Install WP test suite.
printf "Installing WordPress %s Test Suite...\n" "$WP_TS_VERSION"
if download_test_suite "$TS_ARCHIVE" "$WP_TS_VERSION"; then
rsync -a --delete "/tmp/tmp-wordpress-tests-lib/" "$WP_TESTS_DIR"
else
if [[ 'trunk' = "$TS_ARCHIVE" ]]; then
printf "%s\n" "$QUIT"
exit_script
fi
printf "Installing Test Suite from trunk...\n"
if download_test_suite "trunk" "trunk"; then
rsync -a --delete "/tmp/tmp-wordpress-tests-lib/" "$WP_TESTS_DIR"
else
printf "%s\n" "$QUIT"
exit_script;
fi
fi
# Update credentials in the wp-tests-config.php file.
if [[ -f "$WP_TESTS_DIR/wp-tests-config.php" ]]; then
printf "Updating wp-tests-config-sample.php...\n"
if [[ $(uname -s) == 'Darwin' ]]; then
ioption='-i .bak'
else
ioption='-i'
fi
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/youremptytestdbnamehere/wordpress_test/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/yourusernamehere/root/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/yourpasswordhere/root/" "$WP_TESTS_DIR/wp-tests-config.php"
fi
# Install database if it doesn't exist.
printf "Checking if database wordpress_test exists\n"
# Suppress password warnings. It silly I know :-)
printf "[client]\npassword=root\nuser=root" > "/tmp/my.cnf"
database=$(mysqlshow --defaults-file="/tmp/my.cnf" wordpress_test | grep -v Wildcard | grep -o wordpress_test)
if ! [[ "wordpress_test" = "$database" ]]; then
printf "Creating database wordpress_test\n"
mysqladmin --defaults-file="/tmp/my.cnf" create "wordpress_test" --host="localhost"
else
printf "Database wordpress_test already exists\n"
fi
if [[ -f "$WP_TESTS_DIR/wp-tests-config.php" ]]; then
# VVV has the tests config outside the $WP_TESTS_DIR dir.
cp "$WP_TESTS_DIR/wp-tests-config.php" "/tmp/wp-tests-config.php"
fi
# Cleanup files.
clean_up_temp_files
printf "\nFinished setting up packages\n\n"
@tarecord

This comment has been minimized.

Copy link

tarecord commented Jan 9, 2018

This is awesome! Thanks!

@JJJ

This comment has been minimized.

Copy link

JJJ commented Aug 20, 2018

Still works. Thanks keesiemeijer! 👍

@hazephase

This comment has been minimized.

Copy link

hazephase commented Sep 6, 2018

When I run bash setup-phpunit.sh I get

Could not install packages
No network connection detected

@rgadon107

This comment has been minimized.

Copy link

rgadon107 commented Sep 17, 2018

@hazephase In the Terminal, make sure that the shell script ( setup-phpunit.sh) is located in the /app directory. If it's it in a different directory (for example /app/a888f3d9609478b310c2d952644891ba/setup-phpunit.sh, you will not be able to open and execute the target script. It's just a matter of relocating the shell script (once it's been installed to your project) to the root of the /app directory. Then call the script. It should install easily and quickly.

@keesiemeijer

This comment has been minimized.

Copy link
Owner Author

keesiemeijer commented Sep 27, 2018

@hazephase I've updated the script (revision 15) to look if packages are installed instead of checking the internet connection. It should work with the Local app version 2.4.2

@iCaspar

This comment has been minimized.

Copy link

iCaspar commented Sep 28, 2018

Thanks for this @keesiemeijer, 👍 for the fix!

@JJJ

This comment has been minimized.

Copy link

JJJ commented Oct 16, 2018

Continues to work with Local Environment 1.3.1. 🤗

@keesiemeijer

This comment has been minimized.

Copy link
Owner Author

keesiemeijer commented Feb 2, 2019

revision 17 — The default PHPUnit version is updated to 6 for PHP versions 7+

See ticket https://core.trac.wordpress.org/ticket/43218

@keesiemeijer

This comment has been minimized.

Copy link
Owner Author

keesiemeijer commented Feb 4, 2019

Since revision 19 you can use specific options for PHPUnit, WordPress and the WordPress test suite. Use the options
--phpunit-version, --wp-version, --wp-ts-version and --update-packages.

use bash setup-phpunit.sh --help for more information

@DevinWalker

This comment has been minimized.

Copy link

DevinWalker commented Mar 7, 2019

So easy and simple! Thanks @keesiemeijer

@mintplugins

This comment has been minimized.

Copy link

mintplugins commented Mar 7, 2019

When I try and test with phpunit -version, I am getting this response:

Fatal error: Cannot use PHPUnit\Framework\MockObject\Stub as Stub because the name is already in use in phar:///usr/local/bin/phpunit/phpunit-mock-objects/Builder/InvocationMocker.php on line 16

Does anybody know what might be going on here?

@mintplugins

This comment has been minimized.

Copy link

mintplugins commented Mar 7, 2019

It must have been an old version of phpUnit already installed. I spun up a new site in LocalByFlywheel and started over, and all is working 👍 Thanks!

On my old LocalByFlywheel site, I uninstalled PHPunit by running this before any of the steps here, and it fixed my issue:

sudo rm -r /usr/local/bin/phpunit

Update: Today I just ran into this again on a separate LocalByFlyWheel, and had to upgrade PHP to 7.2 to fix this.

@kurudrive

This comment has been minimized.

Copy link

kurudrive commented Apr 23, 2019

Thanks!!!!!!!!!!
I am so happpppppyyyyyyyyyyyy!!!!!!!
Yeahhhhhhhhhhhhhhhhhhhhhhh!!!!!!!!

@DrewAPicture

This comment has been minimized.

Copy link

DrewAPicture commented May 11, 2019

@keesiemeijer This is dope. Thank you!

@iamlasse

This comment has been minimized.

Copy link

iamlasse commented May 23, 2019

This is amazing! Thanks for putting in the work!!!

@alexstandiford

This comment has been minimized.

Copy link

alexstandiford commented Jun 3, 2019

I've used this several times, and it has worked like a charm, however when working with it today I ran into an error when I run phpunit --version:

Fatal error: Cannot use PHPUnit\Framework\MockObject\Stub as Stub because the name is already in use in phar:///usr/local/bin/phpunit/phpunit-mock-objects/Builder/InvocationMocker.php on line 16

I was able to fix this by updating my PHP version to at least 7.1.4, and that fixed it.

@keesiemeijer

This comment has been minimized.

Copy link
Owner Author

keesiemeijer commented Jun 3, 2019

@alexstandiford I think it depends what PHPUnit version you were using. See here what versions are compatible with what PHP versions. https://phpunit.de/supported-versions.html

You could've also have downgraded the PHPUnit version to make it compatible (I think).

bash setup-phpunit.sh --phpunit-version=4

Maybe I could automate that in the script itself?

@alexstandiford

This comment has been minimized.

Copy link

alexstandiford commented Jun 3, 2019

@keesiemeijer You probably could automate that, actually. Since you're already fetching the php version in your script, you could probably associate which version of phpunit should be used to the php-version if the ---phpunit-version isn't set?

@keesiemeijer

This comment has been minimized.

Copy link
Owner Author

keesiemeijer commented Jun 4, 2019

@alexstandiford I found out why you've gotten this error. PHPUnit 6 is not compatible with PHP 7.0.3 (shipped with the Local app). It is however compatible with PHP 7.0.13 and up.

In the latest revision (22) it installs PHPUnit 7 for PHP 7.1 and up, PHPUnit 5 for PHP 7.0, and PHPUnit 4 for all other versions.

@alexstandiford

This comment has been minimized.

Copy link

alexstandiford commented Jul 24, 2019

If you happen to be using this workflow to set up PHPUnit with PHPStorm:
https://localbyflywheel.com/community/t/local-phpunit-phpstorm/6203/16

You can set it up pretty fast using this script along with a really basic script I tossed together from the instructions provided by Clay.

  1. Set up ports as detailed in step 1 in the link above
  2. open site SSH and run this script.
    https://gist.github.com/alexstandiford/0728ba7b21caa323a5ecf67c6e98abd2
  3. Restart local
  4. Open site SSH and run this script.
  5. Start on step 4 in the link above.
@afragen

This comment has been minimized.

Copy link

afragen commented Jul 25, 2019

@keesiemeijer With MacOS Terminal moving to a default of zsh in Catalina MacOS 10.15, is there any need to adapt this script?

@alexstandiford

This comment has been minimized.

Copy link

alexstandiford commented Jul 25, 2019

@afragen I don't think so. I've been running zsh instead of bash with this script for a little while now and it's been working as-expected.

@afragen

This comment has been minimized.

Copy link

afragen commented Jul 25, 2019

Thanks for the confirmation @alexstandiford

@afragen

This comment has been minimized.

Copy link

afragen commented Jul 28, 2019

FYI, I had to make a number of changes to @keesiemeijer's excellent script to make it work with Local Lightning. You can find my modifications at https://github.com/afragen/setup-phpunit/blob/lightning/setup-phpunit.sh

I put a blog post on using WordPress Core Development with Local Lightning.

@alexstandiford

This comment has been minimized.

Copy link

alexstandiford commented Aug 2, 2019

FYI, I had to make a number of changes to @keesiemeijer's excellent script to make it work with Local Lightning. You can find my modifications at https://github.com/afragen/setup-phpunit/blob/lightning/setup-phpunit.sh

I put a blog post on using WordPress Core Development with Local Lightning.

I was just thinking about this the other day. Thanks for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.