Skip to content

Instantly share code, notes, and snippets.

@weierophinney
Created February 11, 2014 20:17
Show Gist options
  • Save weierophinney/8943217 to your computer and use it in GitHub Desktop.
Save weierophinney/8943217 to your computer and use it in GitHub Desktop.
PHPUnit test runner using inotifywait
#!/bin/zsh
#
# Copyright (c) 2014, Joshua Thijssen
# Copyright (c) 2014, Matthew Weier O'Phinney
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the <organization> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
# Usage: rtut.sh [-t TESTDIRECTORY] [-p TESTPREFIX] [-e EXCLUDE] [-a] [-h]
#
# -t TESTDIRECTORY Name of the subdirectory containing tests; defaults to ./tests
# -p TESTPREFIX Alternate subdirectory prefix to use, if test and source hierarchy differ
# -e EXCLUDE Do not run tests if a changed file matches this pattern
# -a Run all tests on every change
# -h The usage message
#
# Real-time PHPUnit tester. Leave this script running inside a zsh shell to get
# instant feedback whenever a file or unit-test file changes.
O_TESTDIR="./tests"
O_TESTPREFIX=""
O_EXCLUDE=""
RUNALL=""
HELP=""
zparseopts -K -E t:=O_TESTDIR p:=O_TESTPREFIX a=RUNALL h=HELP e:=O_EXCLUDE
if [[ "$HELP" != "" ]]
then
echo Usage: $(basename "$0") "[-t TESTDIRECTORY] [-p TESTPREFIX] [-e EXCLUDE] [-a] [-h]"
echo "-t TESTDIRECTORY Name of the subdirectory containing tests; defaults to ./tests"
echo "-p TESTPREFIX Alternate subdirectory prefix to use, if test and source hierarchy differ"
echo "-e EXCLUDE Do not run tests if a changed file matches this pattern"
echo "-a Run all tests on every change"
echo "-h Usage; this message"
exit 0
fi
TESTDIR=$O_TESTDIR[2]
TESTPREFIX=$O_TESTPREFIX[2]
EXCLUDE=$O_EXCLUDE[2]
if [[ $(echo ${TESTDIR} | cut -c-2) != "./" ]]
then
TESTDIR="./${TESTDIR}"
fi
TESTDIRSTRLEN=${#${TESTDIR}}
if [ "$EXCLUDE" != "" ]
then
EXCLUDE=".*${EXCLUDE}.*"
fi
inotifywait -m . -q -r --exclude=".*sw[px]" --exclude=".*un\~" --format "%w%f" -e close_write | while read line
do
# Check if our file ends with .php
if [[ ! $line =~ ".php$" ]]
then
continue;
fi
if [ "$EXCLUDE" != "" ]
then
if [[ $line =~ "$EXCLUDE" ]]
then
continue;
fi
fi
if [ "$RUNALL" != "" ]
then
(cd $TESTDIR ; phpunit);
continue;
fi
FILESTRLEN=${#${line}}
if [ $FILESTRLEN -lt $TESTDIRSTRLEN ]
then
TESTFILE=$(echo ${line} | sed -re 's/^\.\/[^\/]+\///')
TESTFILE=$(echo $TESTFILE | sed -re 's/.php$/Test.php/')
if [ "${TESTPREFIX}" != "" ]
then
TESTFILE=$(echo $TESTFILE | sed -re "s/^[^/]+/${TESTPREFIX}/")
fi
elif [ `echo $line | cut -c-${TESTDIRSTRLEN}` != $TESTDIR ]
then
TESTFILE=$(echo ${line} | sed -re 's/^\.\/[^\/]+\///')
TESTFILE=$(echo $TESTFILE | sed -re 's/.php$/Test.php/')
if [ "${TESTPREFIX}" != "" ]
then
TESTFILE=$(echo $TESTFILE | sed -re "s/^[^/]+/${TESTPREFIX}/")
fi
else
(( CUTLEN = $TESTDIRSTRLEN + 2 ))
TESTFILE=$(echo ${line} | cut -c${CUTLEN}-)
fi
# Test file is not found
if [ ! -f "${TESTFILE}" ] ; then
continue;
fi
(cd $TESTDIR ; phpunit ${TESTFILE})
done
@weierophinney
Copy link
Author

This is based on https://github.com/jaytaph/RealTimePHPUnit.git but updated to add:

  • ability to specify the test path as an optional, named argument
  • ability to specify a custom test "prefix". This is useful if your source and test directories are not 1:1 mirrors. As an example, in ZF2, we use library/Zend/, but the test directory uses tests/ZendTest; in this case, you'd pass -p ZendTest so that it will replace Zend with ZendTest when trying to identify the test file.
  • ability to specify a filesystem pattern that should be omitted when scanning for test changes. As an example, in zf-apigility-admin, the testing harness writes to files under TestAsset directories; I thus specify -e TestAsset to exclude those from triggering test runs.
  • ability to tell the listener to run all tests, vs. just those that match the file being saved (-a).
  • only trigger on writes (move/create meant that I was often triggering 3-4 times per write).

To do this, I used zsh's zparseopts built-in, which made the options parsing dead-simple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment