Monday, February 22

Using PhpUnit with NetBeans

With the boom of TDD is amazing how slowly the IDEs are integrating unit testing to their features, for PHP I've only found a few, and the best result (for me at least) was using NetBeans.

Here we'll cover how to install PHPunit and integrate it into NetBeans

First, as always install some application we'll need in the future
$ sudo apt-get install php5-dev php-pear

If you installed xdebug from ubuntu repositories you'll need to remove it
$ sudo apt-get remove php5-xdebug

Now discover phpunit servers
$ sudo pear channel-discover pear.phpunit.de
$ sudo pear channel-discover pear.symfony-project.com

And install it
$ sudo pear install --alldeps phpunit/PHPUnit

I strongly recommend installing xdebug
$ sudo pecl install xdebug


Now that you have phpUnit installed just need to add some generic tests to your project, what I've used is

1. Create a tests directory on the project root
$ mkdir tests

2. Create a php file that will recursively load all the files in the directory and run a class of phpUnit to run all the classes loaded, some proposed content is displayed here.
$ kate allTests.php
//add the phpunit framework
require_once 'PHPUnit/Framework.php';

//including all the files available in the current directory
$filesIncluded = array();
includeRecurse('tests', $filesIncluded);

//generic class
class phpucAllTests
{
public static function suite()
{
$suite = new PHPUnit_Framework_TestSuite('Package');
foreach ($GLOBALS['filesIncluded'] as $fileincluded)
{
$filename = explode('.', $fileincluded);
$suite->addTestSuite($filename[0]);
}
return $suite;
}
}

3. Any file inside the tests directory should be something like:
class InstallJobTest extends PHPUnit_Framework_TestCase
{
public function testAapplyFilters()
{
//test the null query
$query = null;
InstallJob::applyFilters($query);
$sql = $query->getSQL();
$this->assertRegExp('/^SELECT (.*) FROM InstallJob/', $sql);

//Testing club number filter
$this->clubNumberFilterTests();

//Testing installation companies
$this->installationCompanyFilterTests();
}
}

Now that all the required files are created, it's time to test the phpUnit

Open a console and into your project directory run
$ phpunit tests/allTests.php

If all is working is time to use NetBeans

Select the project in the "Projects" panel and right click it, select "test" from the context menu.


A dialog will open prompting for a unit test folder, select the tests directory you created

Now below "Source Files" a new item called "Test Files" appear with the contents of the tests directory

To run the tests right click allTests.php file and select "run" from the context menu


NetBeans will display some useful information such as the code coverage, executed test cases, asserts, etc.

Thursday, February 18

Installing PHPunderControl in ubuntu

First of all we need to install the applications and extensions we need
$ sudo apt-get install gitosis php5-dev
$ sudo pear channel-discover pear.phpunit.de
$ sudo pear channel-discover pear.symfony-project.com
$ sudo pear install --alldeps phpunit/PHPUnit

Now we have to download CruiseControl, pick any method you want, here a wget example
$ wget http://downloads.sourceforge.net/project/cruisecontrol/CruiseControl/2.8.3/cruisecontrol-bin-2.8.3.zip?use_mirror=ufpr

We must unzip the downloaded file, I'm decompressing it directly where it will reside
$ sudo unzip cruisecontrol.zip /opt

Now we must create a group and user for the system
$ sudo groupadd cimasters
$ sudo useradd -G cimasters cimaster

Change the owner of CruiseControl files
$ sudo chown cimaster:cimasters /opt/cruisecontrol* -R

Create a script to launch it directly as a service
$ sudo kate /etc/init.d/cruisecontrol

with the contents
#!/bin/sh
CC_USER=cimaster
CC_INSTALL_DIR=/opt/cruisecontrol
CC_WORK_DIR=$CC_INSTALL_DIR
CC_LOGFILE_DIR=$CC_INSTALL_DIR
export JAVA_HOME=/opt/jdk1.5.0_11
PATH_ADDITIONS=
CC_WEBPORT=8484
CC_JMXPORT=8888
CC_RMIPORT=8585
NAME=cruisecontrol
DESC="CruiseControl - continuous integration build loop"
PATH=/usr/lib/jdk/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/bin:/bin
if [ -n "$PATH_ADDITIONS" ]; then
PATH=$PATH_ADDITIONS:$PATH
fi
export PATH
CC_DAEMON=$CC_INSTALL_DIR/cruisecontrol.sh
CC_CONFIG_FILE=$CC_INSTALL_DIR/config.xml
CC_LOG_FILE=$CC_LOGFILE_DIR/cruisecontrol.log
CC_COMMAND="cd $CC_WORK_DIR; $CC_DAEMON -configfile $CC_CONFIG_FILE -webport $CC_WEBPORT -jmxport $CC_JMXPORT"
if [ -f /etc/default/cruisecontrol ]; then
. /etc/default/cruisecontrol
fi
test -f $CC_DAEMON || (echo "The executable $CC_DAEMON does not exist!" && exit 0)
if [ `id -u` -ne 0 ]; then
echo "Not starting/stopping $DESC, you are not root."
exit 4
fi
PARPID=`ps -ea -o "pid ppid args" | grep -v grep | grep "${CC_DAEMON}" | sed -e 's/^ *//' -e 's/ .*//'`
if [ "${PARPID}" != "" ]
then
PID=`ps -ea -o "pid ppid args" | grep -v grep | grep java | grep "${PARPID}" | \
sed -e 's/^ *//' -e 's/ .*//'`
fi
case "$1" in
'start')
env >> cc.startup.env
su $CC_USER -c "/bin/sh -c \"$CC_COMMAND >> $CC_LOG_FILE 2>&1\"" & RETVAL=$?
echo "$NAME started with jmx on port ${CC_JMXPORT}, web on ${CC_WEBPORT}, rmi on ${CC_RMIPORT}"
;;
'stop')
if [ "${PID}" != "" ]; then
kill -9 ${PID} ${PARPID}
$0 status
RETVAL=$?
else
echo "$NAME is not running"
RETVAL=1
fi
;;
'status')
# echo PARPIDs $PARPID
# echo PIDs $PID
kill -0 $PID >/dev/null 2>&1
if [ "$?" = "0" ]; then
echo $NAME \(pids $PARPID $PID\) is running
RETVAL=0
else
echo "$NAME is stopped"
RETVAL=1
fi
;;
'restart')
$0 stop && $0 start
RETVAL=$?
;;
*)
echo "Usage: $0 { start | stop | status | restart }"
exit 1
;;
esac
#echo ending $0 $$....
exit 0

Give it permissions to run
$ sudo chmod +x /etc/init.d/cruisecontrol

For some reason, there are some hardcoded scripts and some failures in setting the java_home, so to take a sortcut, we'll just create symlinks to the correct places
$ sudo ln -s /usr/lib/jdk/ /opt/jdk1.5.0_11
$ sudo ln -s /usr/lib/jdk/bin/java /bin/java

With this CruiseControl should be ready to run
$ sudo service cruisecontrol start

The message tells us which ports are being used, to change them modify the script in /etc/init.d/

Now PHPunderControl
We create a temp directory
$ cd ~ && mkdir phpundercontrol && cd phpundercontrol

We'll download from the git repository
$ git clone git://github.com/manuelpichler/phpUnderControl.git

Now we only need to install it
$ cd phpUnderControl/bin && sudo php phpuc.php install /opt/cruisecontrol/

With this PHPunderControl should be ready, we only need to restart CruiseControl
$ sudo service cruisecontrol restart

Now we need a project, we have to go to the cruise control directory to create the directories
$ cd /opt/cruisecontrol/projects && sudo mkdir project && cd project

The folder will need sublic acces so CruiseControl can execute and write
$ sudo chmod -rv 777 ./

One we have the project directory we must create some directories for the builds and source code
$ mkdir source && mkdir build && mkdir build/api && mkdir build/coverage && mkdir build/logs

Now inside source directory, we'll download our code from our subversion server
$ cd source && svn co http://localhost/svn/trunk/

Now we have to create the build configurations for the project
$ cd .. && kate build.xml

And put the following code, the idea is that build will require all the other actions
1. update the code from svn
2. generate documentation
3. sniff the code looking for errors
4. apply phpunit test cases, the phpunit will look for a class phpucAllTests inside source/tests/AllTests.php

<?xml version="1.0" encoding="UTF-8"?>
<project name="project" basedir=".">
  <target name="checkout">
    <exec executable="svn" dir="${basedir}/source">
      <arg line="up" />
    </exec>
  </target>

  <target name="php-documentor">
    <exec executable="phpdoc" dir="${basedir}/source">
      <arg line="-ct type -ue on -t ${basedir}/build/api
           -tb /usr/share/php/phpUnderControl/Data/phpdoc
           -d ./"/>
    </exec>
  </target>

  <target name="php-codesniffer">
    <exec executable="phpcs"
          dir="${basedir}/source"
          output="${basedir}/build/logs/checkstyle.xml">
      <arg line="--report=checkstyle
           --standard=PEAR
           --ignore=src/autoload src/"/>
    </exec>
  </target>

  <target name="phpunit">
    <exec executable="phpunit" dir="${basedir}/source" failonerror="off">
      <arg line="--log-xml ${basedir}/build/logs/phpunit.xml
           --log-pmd ${basedir}/build/logs/phpunit.pmd.xml
           --log-metrics ${basedir}/build/logs/phpunit.metrics.xml
           --coverage-xml  ${basedir}/build/logs/phpunit.coverage.xml
           --coverage-html ${basedir}/build/coverage
           phpucAllTests tests/AllTests.php" />
    </exec>
  </target>

  <target name="build"
          depends="checkout,php-documentor,php-codesniffer,phpunit" />
</project>


We can test our build typing
$ ../../apache-ant-1.7.0/bin/ant build

Now we just need to add the project to the cruise control configuration file
$ cd ../.. && kate config.xml

add the following code inside tags, the name of the project should be the same as the name of the directory containing the build and source directories

<cruisecontrol>
<project name="project" buildafterfailed="true">
  <plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN" />
  <modificationset quietperiod="60">
    <svn localWorkingCopy="projects/${project.name}/source/"/>
  </modificationset>
  <bootstrappers>
    <svnbootstrapper localWorkingCopy="projects/${project.name}/" file="build.xml"/>
  </bootstrappers>
  <schedule interval="300">
    <ant anthome="apache-ant-1.7.0" buildfile="projects/${project.name}/build.xml"/>
  </schedule>
  <listeners>
    <currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
  </listeners>
  <log dir="logs/${project.name}">
    <merge dir="projects/${project.name}/build/logs/"/>
  </log>
  <publishers>
    <artifactspublisher dir="projects/${project.name}/build/api" dest="artifacts/${project.name}" subdirectory="api"/>
    <artifactspublisher dir="projects/${project.name}/build/coverage" dest="artifacts/${project.name}" subdirectory="coverage"/>
    <execute command="phpuc graph logs/${project.name} artifacts/${project.name}"/>
  </publishers>
</project>
</cruisecontrol>

And that's it ... more simple than it looks ...