Tag Archives: phpunit

Test your code like a pro – PHPUnit in practice – preparation guide

As promised, here’s a quick guide that will allow you to prepare for my “Test your code like a pro – PHPUnit in practice” tutorial at PHPNW12 conference in Manchester on 5th October. If you still haven’t decided whether to go or not have a look at the official abstract and my previous blog posts. There is still time to get the tickets!

There are really 2 things that you will need, to get smoothly through the tutorial: git client and working installation of PHPUnit. So please make sure you have installed them and you can use them. Being able to open PDF files is also recommended as I will be giving out a tutorial’s manual/instructions in a PDF format.

Well this above obviously requires a computer. I guess you will decide to bring a laptop with you, although if you prefer to take your desktop computer with you, it will do too. While most of the stuff will be in the PDF file, going through the tutorial without a laptop will be difficult to follow and you will not learn as much. I will not have any spare laptops to borrow, sorry.

I strongly discourage brining in a Windows machine with you, unless you feel comfortable with solving any problems related with php, pear and PHPUnit in a very short period of time or you come really well prepared. We will not have a lot of time to spend configuring each other machines and we also don’t want the others to wait and do nothing while you set everything up. We only have 3 hours, and believe me it will go fast.

Ubuntu/Debian

git

Using apt to install git should set you up pretty quickly. Just type in the below:

$ sudo apt-get install git-core
$ git --version

PHP

You will need at least PHP 5.3.3 installed, but I strongly recommend installing PHP 5.4. Again with apt it should be pretty instant to get you set up:

$ sudo apt-get install php5-cli
$ sudo apt-get install php-pear
$ sudo apt-get install php5-xdebug
$ php -v

PEAR

Before you can install PHPUnit you need to make sure PEAR is at the latest version. So upgrade it first

$ sudo pear upgrade PEAR

PHPUnit

Then finally you will be able to install PHPUnit:

$ sudo pear config-set auto_discover 1
$ sudo pear install pear.phpunit.de/PHPUnit
$ phpunit --version

Windows

git

You can install git client on a Windows machine by using the installer package that you can download from msysgit project downloads page.

Just accept all the default options. All you really need is to be able to clone a repo and change branches.

PHP

  1. First download PHP 5.4 binaries from http://windows.php.net/ and unzip it into c:\php.
  2. Then download xdebug library from xdebug downloads page and copy it over to c:\php\ext directory.
  3. Rename the library to php_xdebug.dll.
  4. Copy c:\php\php.ini-development to c:\php\php.ini
  5. Make sure date.timezone is set to “Europe/London”
  6. Activate xdebug by adding the snippet bellow at the end of c:\php\php.ini
  7. [xdebug]
    zend_extension=ext\php_xdebug.dll
  8. Add c:\php to system path via Computer’s Advanced Properties -> Environment Variables
  9. Restart windows
  10. In the command prompt run:
  11. c:\> php -v
    PHP 5.4.7 (cli) (built: Sep 12 2012 23:48:31)
    Copyright (c) 1997-2012 The PHP Group
    Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
        with Xdebug v2.2.1, Copyright (c) 2002-2012, by Derick Rethans

PEAR

Next we have to install PEAR.

  1. Download go-pear.phar from http://pear.php.net and copy it over to c:\php\
  2. Run the following command and from the presented options change option 1 – Installation base to c:\php and option 11 – Name of configuration file to c:\php\pear.ini
  3. c:\> php c:\php\go-pear.phar
  4. Then hit enter to finish installation
  5. Let installer change your include path at the end by answering y to the question “Would you like to alter php.ini?”
  6. Double-click the PEAR_ENV.reg file in c:\php
  7. Reboot again to make sure PEAR_ENV registry entries have taken effect

PHPUnit

Finally it’s time to install PHPUnit. At this point just running the below should set you up.

c:\> pear config-set auto_discover 1
c:\> pear install pear.phpunit.de/PHPUnit

c:\> phpunit --version
PHPUnit 3.7.0 by Sebastian Bergmann.

If at any point you have a problem with installing it all on Windows please drop me an email. You can also have a look at Stu Herbert’s blog post about Getting PEAR working on Windows 7

I hope this short guide will let you come to my tutorial well prepared. I will see you in Manchester soon!

The Grumpy Programmer’s Book at PHPNW12

I’ve got some good news for the people that already have decided to attend my tutorial “Test your code like a Pro – PHPUnit in practise” at PHPNW12 conference in ManchesterChris Hartjes has kindly offered to give away 3 digital copies of his famous “Guide To Building Testable Applications in PHP” book to attendees of my tutorial! I strongly believe this will nicely compliment the tutorial itself and give the people such a boost in their further adventures with testing. You can learn more about the book itself at http://www.grumpy-testing.com/.

Your still have a chance to get a ticket to my tutorial on 5th October and only one more reason to buy it! For these who already know PHPUnit and already have started they journey through unit testing PHP code I strongly recommend buying the book and reading it. There is plenty of hints and tips that will help you understand how to write unit testable code and increase its quality!

Big thanks to Chris again and I hope to see you all in Manchester soon!

Test your code like a pro – PHPUnit in practice at PHPNW12

PHP NW12 conference is nearly upon us, so I guess it’s about time to tell you more about the workshop that I will be having there on the 5th October morning. I wanted to do that for a very long time, especially that I am a big fan of quality assurance in software engineering. You can read the official abstract at the conference homepage, but here I am gonna tell you a little bit more about what we gonna do during the 3 hour tutorial.

My main focus will be to teach you and lead you through main concepts of unit testing PHP code. It’s a beginners course, so we will go though all the basics of organising your test suite, understanding the benefits of unit tests and making you feel comfortable and confident with the code you write. We’ll do it all big band TDD style – so we will write the tests first and implement the functionality afterwards. It’s very important to get this right and to set up the mindset from the very beginning.

PHPUnit is de-facto a standard in PHP world, so it is also important that you are aware of the main features of the tool. We’ll go through the set up, configuration and options that are the most useful at the beginning – so you can get the most out of the tool. The concepts that I am gonna go through will include:

  • working with typical test suites
  • basic assertions – strings, integers, booleans, object
  • PHPUnit from the command line
  • using phpunit.xml configuration file
  • testing exceptions
  • testing PHP errors, warnings and notices
  • asserting output
  • data driving your tests by using data providers
  • generating code coverage report

If you have never had a chance to unit test your code, but you’d like to try now, it’s the best time to get started. I will do my best to make you feel confident and to help you start your own Journey Towards Continuous Integration, but what you have to do is to go to your boss and convince him to buy you a ticket to my tutorial ( and the conference). There is still plenty of time and there are still some tickets left.

No matter whether you have already bought a ticker or you’re thinking about right now, if there is anything specific you you want me to go through during the tutorial please let me know. I’ll do my best to fit that in. We can also change the course of the tutorial if the group will prefer to touch on some slightly different subjects of unit testing – I am open for suggestions. And I will be accessible after the tutorial too, for any questions, help or even quick hacks. You will even get more chances to speak to me over the next 2 days, during the main conference days – on the 6th and 7th October.

It’s a lot of things to go through so it is very important that you come prepared and focused on the day. We only have 3 hours and I’d like to avoid situation where the hardware/operational issues will stand in our way. While I will try to help everybody out if there are any issues I will encourage you to install PHPUnit on your laptops before, so it is working without a problem. I want to focus on writing the tests and using PHPUnit, not on trying to make PHP itself working on your machines.  I strongly recommend using a non-Windows system. Windows has been proved to be very unreliable if it comes to setting up PHP and PEAR. It does work, but it requires some strong skills and patience. So you’d rather install ubuntu or debian, as this is an environment that everything just works out of the box.

During the course of the next 2 days I will post more detailed instructions about how you can prepare your laptops to make sure you can run PHPUnit on them without any issues, so watch this space closely.

I hope to see you at my tutorial in about 3 weeks!

PHPUnit assertion gotcha

A recent discovery. If you found yourself upgrading from PHPUnit 3.5.x to PHPUnit 3.6.x be aware of a subtle change. assertEquals() and I guess all related assertions will behave a bit differently after the upgrade. When you assert 2 values and one of them is an object with defined __toString() function PHPUnit 3.5.x will fail the test, while PHPUnit 3.6 will happily pass it (by I am guessing converting the object to string). See an example on gisthub for more details:

$ phpunit testCaseTest.php
PHPUnit 3.5.15 by Sebastian Bergmann.
F.
Time: 1 second, Memory: 4.50Mb
There was 1 failure:
1) TestCase::testAssertStringWithObject
Failed asserting that
myClass Object
(
)
matches expected .
/private/tmp/Testing/testCaseTest.php:16
FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
$ phpunit testCaseTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.
..
Time: 1 second, Memory: 5.50Mb
OK (2 tests, 2 assertions)

Autotesting with watchr, growl and PHPUnit

Inspired by a conversation at the office couple of days ago with a slightly bald software developer from the UK and @Stubbs I decided to play a bit with the concept of autotesting. I came across it about a year a go during BTDevCon and I really liked it, but back then I have seen it in action, when one of the developers was using it for a demo in Ruby. I haven’t heard about anything similar for PHP so I didn’t dig in further. Until now.

Let’s get back to the concept of autotesting again for a minute.  The other term for it is continuous testing and in short it is about getting an instant feedback on your code while you’re developing it. In practise, the test suite is being triggered every single time you save a file and the results of the run are displayed on the screen. You don’t have to run the test suite manually, it is done for you.

All you need is watchr, growl and growlnotify (which is available as part of Growl Extras). Watchr is a flexible tool that allows you to watch the filesystem and run an arbitrary command when a change is detected, growl is a notification system for Mac OS X and growlnotify is a command-line tool to post Growl notifications.

Watchr

To install watchr you can either install it using gem:

#> sudo gem install watchr
Successfully installed watchr-0.7
1 gem installed
Installing ri documentation for watchr-0.7...
Installing RDoc documentation for watchr-0.7...

or clone the latest version from github, generate the gem and install it from your local disk:

#> git clone git://github.com/mynyml/watchr.git
#> cd watchr
#> gem build watchr.gemspec
   Successfully built RubyGem
   Name: watchr
   Version: 0.7
   File: watchr-0.7.gem
#> sudo gem install watchr-0.7.gem
Successfully installed watchr-0.7
1 gem installed
Installing ri documentation for watchr-0.7...
Installing RDoc documentation for watchr-0.7...

Growl and growlnotify

Growl (with included extras) is available from its home page as a standard dmg image. Just follow onscreen installation instructions.

Setup watchr with PHPUnit

To set up watchr with PHPUnit you only need one configuration file. In there, you define which part of the filesystem you want to watch for changes and what do you want to do when the change occurs. In my case all I want is to execute my test suites. So here is the example file, called watchr.rb and stored in the top level directory of my module:

In the first line, I have set up watchr to watch any file with php extension for incoming changes and when it detects the change to execute code_changed() function. code_changed() does nothing else but executes phpunit command in my Test subdirectory and passes the results to growl() function.  And the growl() function basically parses the results, checks whether tests run successfully or not and executes growlnotify with an appropriate message and image.

Let the fun begin!

All you have to do now is run watchr, start changing your code and watch for growl notifications!

#> watchr watchr.rb
Positive notification

Positive notification

Failure notification

Failure notification

You can get both the configuration and images I have used from my github. Happy continuous testing!

Sources:

Sonar for PHP coming

sonarI have received a lot of positive feedback after my The Journey towards Continuous Integration talk at PHP NW 2010 conference. It seems that a lot of people have found it both interesting and inspiring. I am really glad. After the talk many people asked me about Sonar which I briefly mentioned and were eager to know more about it. With this blog post I will try to fill the gap in my talk.

Solving the mistery

I have heard about Sonar for the first time about a year ago I think. It looked cool! All the fancy graphs, statistics, numbers… But, first I couldn’t understand how would it actually fit into our development process and secondly it had no support for PHP. A lot of things has changed since then though.

With a continuous integration process nearly in place at work, we now need to properly track the progress not only of the build itself, but also how in overall our code quality changes. We want to know whether the code complies to the rules we have set up, whether over time it gets better and at the same time we want to communicate the progress to the business.  What a surprise for me it was, when I have found out that actually all of that we could achieve with Sonar! And imagine the grin on my face when I was told that there are people that have started working on PHP plugin for Sonar!

Installing Sonar

Installing Sonar is very easy. Sonar runs on any operating system that support Java and Maven. For version 2.1 which I am gonna install you will need Java Development Kit v1.5 or later and Maven 2.0.9+, 2.1.+ or 2.2.+.

If you’re using Ubuntu distribution, just can just follow the instructions below.

To install Sun JDK you need to enable partner repositories first. Just edit /etc/apt/sources.list , uncomment the following lines:

# deb http://archive.canonical.com/ubuntu maverick partner
# deb-src http://archive.canonical.com/ubuntu maverick partner

and install the JDK:

#> sudo apt-get update
#> sudo apt-get install sun-java6-jdk

To install maven you can use apt-get as well:

#> sudo apt-get install maven2

With all the things in place it’s time to download Sonar. You can get it from its download page. Remember that not all plugins are compatible with all Sonar versions, so before you make a decision which version to download check Sonar Compatibility matrix. Because I am gonna use 0.2 version of PHP plugin I will download Sonar 2.1.2.

#> wget http://dist.sonar.codehaus.org/sonar-2.1.2.zip

Installation is as easy as just unpacking the archive:

#> mkdir ~/apps
#> cd ~/apps && unzip /home/proofek/Downloads/sonar-2.1.2.zip

Configuring Sonar

By default Sonar runs with an embedded Apache Derby database. If you want just to play with Sonar or test it then you can just skip the next step, but if you plan to use it later on or you want to install it in a production environment then you better switch to more robust database server like MySQL, Oracle, Postgresql or MS SqlServer. Sonar suports them all. I will install it and configure it with MySQL server.

First, let’s install MySQL server. Again apt comes handy:

#> sudo apt-get install mysql-server

The server should automatically be started after that and should accept any incoming connections. Now we have to create empty database and a user that Sonar will use. Let’s name the database and user sonar and use S0n4rU53r as a password. Obviously it’s up to you how you will call them, just make sure you use the same names later on in Sonar configuration file. Also remember this is only a sample configuration and you might want to configure the access to database differently for security reasons.

#> mysql -uroot -p -e "CREATE DATABASE sonar"
#> mysql -uroot -p -e "CREATE USER 'sonar'@'%' IDENTIFIED BY 'S0n4rU53r'"
#> mysql -uroot -p -e "GRANT ALL ON sonar.* TO 'sonar'@'%'"

Next, edit conf/sonar.properties configuration file, uncomment template for MySQL support and comment out the default Derby configuration.

#sonar.jdbc.url: jdbc:derby://localhost:1527/sonar;create=true
#sonar.jdbc.driver: org.apache.derby.jdbc.ClientDriver
#sonar.jdbc.defaultTransactionIsolation: 1
#sonar.jdbc.validationQuery: values(1)
sonar.jdbc.url: jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8
sonar.jdbc.driver: com.mysql.jdbc.Driver
sonar.jdbc.validationQuery: select 1

At the bottom of that file, in Global database settings section, you can change default database username and password.

sonar.jdbc.username:                       sonar
sonar.jdbc.password:                       S0n4rU53r
sonar.jdbc.maxActive:                      10
sonar.jdbc.maxIdle:                        5
sonar.jdbc.minIdle:                        2
sonar.jdbc.maxWait:                        5000
sonar.jdbc.minEvictableIdleTimeMillis:     600000
sonar.jdbc.timeBetweenEvictionRunsMillis:  30000

If you want to run Sonar on different IP address or port you can configure that at the top of this configuration file:

# Listen host/port and context path (for example / or /sonar). Default values are 0.0.0.0:9000/
#sonar.web.host:                           0.0.0.0
#sonar.web.port:                           9000
#sonar.web.context:                        /

Now we’re ready to start Sonar for the first time. Start  and stop scripts are located in bin directory.

Execute the following script to start the server :

  • on linux/mac : bin/[YOUR PLATEFORM]/sonar.sh start
  • on windows : bin/windows-x86-32/StartSonar.bat

Note that you can also run as a NT service with bin/windows-x86-32/InstallNTService.bat, then bin/windows-x86-32/StartNTService.bat

For Linux start command will look like this:

#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh start

and you stop Sonar like this:

#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh stop

It gets a while to start it for the first time as the database schema is being set up. Have a look at the log file to see the progress and watch for any issues that might prevent Sonar from starting.

#> tail -f ~/apps/sonar-2.1.2/logs/sonar.log

Message like this indicates that application is ready to use:

2010.11.09 21:55:39 INFO  org.sonar.INFO  Sonar started: http://0.0.0.0:9000/

Just browse now to http://localhost:9000/. Sonar is ready to use.

Sonar dashboard

Sonar dashboard (after first run)

Installing PHP plugin

At the moment (mid Nov 2010), only version 0.2 of the plugin has been released, and you can download it from the official plugin site.

It’s split into 5 separate jar files:

  • core PHP plugin
  • PHPUnit plugin
  • PHP_Codesniffer plugin
  • PHP Depend plugin
  • PHP MD plugin
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-plugin/0.2/sonar-php-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-unit-plugin/0.2/sonar-php-unit-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-codesniffer-plugin/0.2/sonar-php-codesniffer-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-depend-plugin/0.2/sonar-php-depend-plugin-0.2.jar
#> wget http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-php-pmd-plugin/0.2/sonar-php-pmd-plugin-0.2.jar

But that’s not all. The plugin actually requires the following tools to be installed on a machine that you are going to analyse your project on (and it actually doesn’t have to be the same machine you install Sonar on):

If you are already using them, you will know how to install/configure them. Only PHP_Codesniffer requires special treatment, so I strongly recommend you follow my installation guide for PHP_Codesniffer below. For those of you, who are not really familiar with these tools yet, here is a quick guide how to set them all up.

PHP + PEAR

Fairly simple installation, especially with apt:

#> sudo apt-get install php5-cli
#> php -v
PHP 5.3.3-1ubuntu9.1 with Suhosin-Patch (cli) (built: Oct 15 2010 14:17:04)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
#> sudo apt-get install php-pear
#> pear list
Installed packages, channel pear.php.net:
=========================================
Package          Version State
Archive_Tar      1.3.7   stable
Console_Getopt   1.2.3   stable
PEAR             1.9.1   stable
Structures_Graph 1.0.3   stable
XML_Util         1.2.1   stable

PHPUnit + Xdebug

Now lets use PEAR installer to install PHPUnit. This is a standard installation procedure for PHPUnit.

#> sudo pear channel-discover pear.phpunit.de
#> sudo pear channel-discover components.ez.no
#> sudo pear channel-discover pear.symfony-project.com
#> sudo pear install --alldeps phpunit/PHPUnit
#> phpunit --version
PHPUnit 3.5.3 by Sebastian Bergmann.

and pecl installer to install Xdebug. We will need php sources and some development tools as well, because pecl will actually compile Xdebug on the fly before installing it. For systems from Ubuntu/Debian family just use apt to install php5-dev package.

#> sudo apt-get install php5-dev

And after that install Xdebug and enable the extension by creating xdebug.ini file with the following content:

#> sudo pecl install xdebug
#> sudo vim /etc/php5/conf.d/xdebug.ini
zend_extension=/usr/lib/php5/20090626+lfs/xdebug.so
xdebug.auto_trace = "Off"
xdebug.collect_params = "On"
xdebug.collect_return = "Off"
xdebug.trace_format = "0"
xdebug.trace_options = "1"
xdebug.trace_output_dir = "/local/tmp/xdebug"
xdebug.trace_output_name = "timestamp"
xdebug.profiler_enable = "0"
xdebug.auto_profile = "1"
xdebug.auto_profile_mode = "6"
xdebug.output_dir = "/local/tmp/xdebug"
xdebug.profiler_output_dir = "/local/tmp/xdebug"
xdebug.profiler_output_name = "timestamp"

Refer to Xdebug documentation for specific configuration options. Let’s just verify now that PHP has Xdebug support.

#> php -v
  PHP 5.3.3-1ubuntu9.1 with Suhosin-Patch (cli) (built: Oct 15 2010 14:17:04)
  Copyright (c) 1997-2009 The PHP Group
  Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
      with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans

PHP_Codesniffer

With PHP_Codesniffer it’s a little bit different. The stable version 1.2.2 which is available now (mid Nov 2010) doesn’t support rulesets yet (but bear in mind version 1.3 will). So guys at SQLi have come up with a work around.

First of all if you already have PHP_Codesniffer installed with version bigger then 1.2.2 you have to uninstall it first. And that’s because we have to install a modified version 1.2.3 of PHP_CodeSniffer. BUT REMEMBER, this is not an official release. It has been created specifically to work with Sonar. So:

#> sudo pear uninstall PHP_CodeSniffer

and

#> wget https://www.assembla.com/spaces/sqlics/documents/dSJnowvZqr35SUeJe5cbLr/download/dSJnowvZqr35SUeJe5cbLr -O PHP_CodeSniffer_1.2.3.tgz
#>  sudo pear install ~/Downloads/PHP_CodeSniffer_1.2.3.tgz
#> phpcs --version
PHP_CodeSniffer version 1.2.3 (stable) by Squiz Pty Ltd. (http://www.squiz.net)

Then we have to download and install SQLi Codesniffer which will work like a bridge between Sonar and PHP_Codesniffer.

#> wget https://www.assembla.com/spaces/sqlics/documents/ak6024vZur34RweJe5cbLA/download/ak6024vZur34RweJe5cbLA -O SQLI_CodeSniffer_0.4.0dev1.tgz
#> sudo pear install /home/proofek/Downloads/SQLI_CodeSniffer_0.4.0dev1.tgz
#> sqlics --version
SQLI_CodeSniffer version 0.4.0dev1 (alpha) by SQLI (http://www.sqli.com)

If for any reasons these links or instructions doesn’t work anymore, check the original instructions at SQLi site.

PHP Depend

PHP Depend installation is also a standard one:

#> sudo pear channel-discover pear.pdepend.org
#> sudo pear install pdepend/PHP_Depend-beta
#> pdepend --version
PHP_Depend 0.9.19 by Manuel Pichler

PHPMD

Same with PHP Mess Detector:

#> sudo pear channel-discover pear.phpmd.org
#> sudo pear install --alldeps phpmd/PHP_PMD-alpha
#> phpmd --version
PHPMD 0.2.7 by Manuel Pichler

With all tools in place, just stop Sonar, copy the jar files to Sonar’s plugins directory (~/apps/sonar-2.1.2/extensions/plugins/) and start Sonar again:

#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh stop
#> cp sonar-php-plugin-0.2.jar sonar-php-codesniffer-plugin-0.2.jar sonar-php-depend-plugin-0.2.jar sonar-php-pmd-plugin-0.2.jar sonar-php-unit-plugin-0.2.jar /home/proofek/apps/sonar-2.1.2/extensions/plugins/
#> ~/apps/sonar-2.1.2/bin/linux-x86-32/sonar.sh start

If you carefully watch logs now you will see the plugins being loaded and set up!

#> tail -f ~/apps/sonar-2.1.2/logs/sonar.log
2010.11.09 22:51:18 INFO  org.sonar.INFO  Load metrics...
2010.11.09 22:51:19 INFO  org.sonar.INFO  cleaning alert thresholds...
2010.11.09 22:51:19 INFO  org.sonar.INFO  Load metrics done: 1118 ms
2010.11.09 22:51:19 INFO  org.sonar.INFO  Load rules...
2010.11.09 22:51:19 INFO  org.sonar.INFO  loading 365 findbugs rules...
2010.11.09 22:51:21 INFO  org.sonar.INFO  loading findbugs extensions...
2010.11.09 22:51:21 INFO  org.sonar.INFO  loading 97 PHP CODESNIFFER rules...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading PHP CODESNIFFER extensions...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading 12 PHP PMD rules...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading PHP PMD extensions...
2010.11.09 22:51:22 INFO  org.sonar.INFO  loading 123 checkstyle rules...
2010.11.09 22:51:23 INFO  org.sonar.INFO  loading checkstyle extensions...
2010.11.09 22:51:23 INFO  org.sonar.INFO  loading 216 pmd rules...
2010.11.09 22:51:25 INFO  org.sonar.INFO  loading pmd extensions...
2010.11.09 22:51:25 INFO  org.sonar.INFO  loading 3 squid rules...
2010.11.09 22:51:25 INFO  org.sonar.INFO  loading squid extensions...
2010.11.09 22:51:25 INFO  org.sonar.INFO  Load rules done: 6566 ms
2010.11.09 22:51:25 INFO  org.sonar.INFO  Load profiles...
2010.11.09 22:51:27 INFO  org.sonar.INFO  loading findbugs profiles...
2010.11.09 22:51:27 INFO  org.sonar.INFO  loading the profile Sonar way with Findbugs/java from findbugs
2010.11.09 22:51:34 INFO  org.sonar.INFO  loading PHP CODESNIFFER profiles...
2010.11.09 22:51:34 INFO  org.sonar.INFO  loading the profile Default Php Profile/php from PHP CODESNIFFER
2010.11.09 22:51:37 INFO  org.sonar.INFO  loading PHP PMD profiles...
2010.11.09 22:51:37 INFO  org.sonar.INFO  loading the profile Default Php Profile/php from PHP PMD
2010.11.09 22:51:38 INFO  org.sonar.INFO  loading checkstyle profiles...
2010.11.09 22:51:38 INFO  org.sonar.INFO  loading the profile Sonar way/java from checkstyle
2010.11.09 22:51:39 INFO  org.sonar.INFO  loading the profile Sonar way with Findbugs/java from checkstyle
2010.11.09 22:51:40 INFO  org.sonar.INFO  loading the profile Sun checks/java from checkstyle
2010.11.09 22:51:43 INFO  org.sonar.INFO  loading pmd profiles...
2010.11.09 22:51:43 INFO  org.sonar.INFO  loading the profile Sonar way/java from pmd
2010.11.09 22:51:47 INFO  org.sonar.INFO  loading the profile Sonar way with Findbugs/java from pmd
2010.11.09 22:51:51 INFO  org.sonar.INFO  loading the profile Sun checks/java from pmd
2010.11.09 22:51:51 INFO  org.sonar.INFO  loading squid profiles...
2010.11.09 22:51:51 INFO  org.sonar.INFO  activating php default profile...
2010.11.09 22:51:51 INFO  org.sonar.INFO  activating java default profile...
2010.11.09 22:51:51 INFO  org.sonar.INFO  Load profiles done: 25681 ms
2010.11.09 22:51:51 INFO  org.sonar.INFO  Start sonar done: 37528 ms
2010.11.09 22:52:12 INFO  org.sonar.INFO  Loading web services...
2010.11.09 22:52:13 INFO  org.sonar.INFO  Sonar started: http://0.0.0.0:9000/

Preparing for analysis

We’re just about to analyse our first project then. How exciting! There is only a few things left before we can start though.

Sonar uses maven to analyse projects and needs a pom file to perform it. A typical pom file for PHP project looks like this:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsichemaLocation="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>group-name</groupId>
    <artifactId>artifact-id</artifactId>
    <name>project-name</name>
    <version>1.0</version>
    <packaging>pom</packaging>
    <build>
        <directory>build-directory</directory>
        <sourceDirectory>source-directory</sourceDirectory>
        <testSourceDirectory>tests-directory</testSourceDirectory>
    </build>
</project>

All you have to do, is to replace underscored values with relevant ones. I’ll show you a complete example of it in a minute.

We need to configure maven first, so it knows how to connect to sonar mysql database. There are two locations, where maven keeps its settings.xml file:

  • The Maven install: $M2_HOME/conf/settings.xml
  • A user’s install: ${user.home}/.m2/settings.xml

Refer to your operating system documentation to find out how maven is installed by default. In Ubuntu/Debian family system global configuration file is in /etc/maven2/settings.xml, while in MacOsX it is in /usr/share/maven/conf/settings.xml.

All we have to do now, is to create custom maven profile and activate it. First locate <profiles> section in the xml file. Although there are a few profile examples inside this section already, they are probably all commented out. We will simply add our profile section to it:

<profiles>
    <!-- profile
    Existing profiles definitions (...)
    -->
    <profile>
        <id>sonar-profile</id>
        <properties>
            <sonar.jdbc.url>jdbc:mysql://localhost:3306/sonar?useUnicode=true&amp;characterEncoding=utf8</sonar.jdbc.url>
            <sonar.jdbc.driver>com.mysql.jdbc.Driver</sonar.jdbc.driver>
            <sonar.jdbc.username>sonar</sonar.jdbc.username>
            <sonar.jdbc.password>S0n4rU53r</sonar.jdbc.password>
        </properties>
    </profile>
</profiles>

Next activate the new profile in activeProfiles section. Remove the comments around this section and just add bolded section to it:

<activeProfiles>
    <activeProfile>sonar-profile</activeProfile>
</activeProfiles>

If there are any profiles activated already there, just simply delete them. They don’t exists anyway and will only cause maven to complain during analysis.

If Sonar has been installed on a separate machine and you want to analyse your project on a different machine, then you will have to adjust sonar.jdbc.url option to point it to the sonar database and at the same time grant relevant permissions to the database itself. Also you have to tell maven how it can access Sonar server by specifying sonar.host.url option in profile section:

<sonar.host.url>http://sonar.server.org/</sonar.host.url>

The last thing we have to do is to switch on a few options and make some tweaks for the PHP plugin itself. Integration with the PHP tools is pretty basic at the moment, but is enough to perform some simple analysis. So I am gonna run Sonar in so called dynamic analysis mode, run the tools manually to create all xml reports, and then run Sonar maven task to parse them and add the results to Sonar dashboard. The only exception will be PHP_CodeSniffer – I will let Sonar run the SQLi version and produce compatible report. Bear in mind in future plugin releases I expect the integration to get much better and then, if  you would like to you will be able to use Sonar to run the tools.

Let’s add the following lines to the maven settings.xml file then:

<profile>
    <id>sonar-profile</id>
    <properties>
        <sonar.jdbc.url>jdbc:mysql://localhost:3306/sonar?useUnicode=true&amp;characterEncoding=utf8</sonar.jdbc.url>
        <sonar.jdbc.driver>com.mysql.jdbc.Driver</sonar.jdbc.driver>
        <sonar.jdbc.username>sonar</sonar.jdbc.username>
        <sonar.jdbc.password>S0n4rU53r</sonar.jdbc.password>
       <sonar.language>php</sonar.language>
       <sonar.dynamicAnalysis>true</sonar.dynamicAnalysis>
       <sonar.phpUnit.analyzeOnly>true</sonar.phpUnit.analyzeOnly>
       <sonar.phpDepend.analyzeOnly>true</sonar.phpDepend.analyzeOnly>
    </properties>
</profile>

Analysing projects with Sonar

I have picked up vfsStream project as an example for analysis. Unfortunately this is the only open source project I have found so far, that requires a minimal effort to get it up and running. I have tried PHPUnit, pdepend, PHP_CodeSniffer, Zend Framework and many many more, but they either fail analysis, they are not compatible with PHPUnit 5.3 yet or they have very custom test suite runners which would need some major changes before we could actually perform analysis.

From my experience so far, Sonar often can not analyse the project because it still has problems parsing coverage report. I expect this to improve in next plugin versions though. Most problems can be solved by stopping using AllTests.php files and properly defining phpunit.xml file with filter whitelist section. I have analysed dosens of projects at work using that approach without a problem.

So let’s get vfsStream sources first:

#> svn checkout http://bovigo.googlecode.com/svn/vfs/trunk/ vfsStream

Let’s make it PHPUnit 3.5 compatible first by removing the following line from src/test/AllTests.php file:

PHPUnit_Util_Filter::addDirectoryToWhitelist(SOURCE_DIR);

Next let’s create a directory we will use to store xml reports in:

mkdir -p build/logs

and run PHPUnit to generate both junit log file and coverage clover report file:

#> phpunit --coverage-clover build/logs/phpunit.coverage.xml --log-junit build/logs/phpunit.xml src/test/AllTests.php
PHPUnit 3.5.3 by Sebastian Bergmann.

............................................................  60 / 169
............................................................ 120 / 169
.................................................

Time: 3 seconds, Memory: 13.75Mb

OK (169 tests, 759 assertions)

Writing code coverage data to XML file, this may take a moment.

vfsStream doesn’t have phpunit.xml file, but fortunately  AllTests.php works just fine.

Now let’s run PHP Depend to create pdepend report.

#> pdepend --phpunit-xml=build/logs/pdepend.xml src/main
PHP_Depend 0.9.19 by Manuel Pichler

Parsing source files:
.........                                                        9

Executing CyclomaticComplexity-Analyzer:
.....                                                          119

Executing ClassLevel-Analyzer:
.....                                                          112

Executing CodeRank-Analyzer:
                                                                10

Executing Coupling-Analyzer:
.......                                                        148

Executing Hierarchy-Analyzer:
......                                                         139

Executing Inheritance-Analyzer:
..                                                              57

Executing NPathComplexity-Analyzer:
.....                                                          119

Executing NodeCount-Analyzer:
......                                                         122

Executing NodeLoc-Analyzer:
......                                                         131

Generating pdepend log files, this may take a moment.

Time: 00:01; Memory: 19.25Mb

With all the reports in place

#> ls -ltr build/logs/
total 184
-rw-r--r--  1 smarek  staff  15565 22 Nov 10:18 pdepend.xml
-rw-r--r--  1 smarek  staff  41787 22 Nov 10:18 phpunit.xml
-rw-r--r--  1 smarek  staff  32455 22 Nov 10:18 phpunit.coverage.xml

it’s time to create pom.xml file based on the template mentioned before. Our pom.xml file will look like this:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsichemaLocation="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.googlecode.bovigo</groupId>
<artifactId>vfsStream</artifactId>
<name>vfsStream</name>
<version>1.0</version>
<packaging>pom</packaging>
<build>
    <directory>build</directory>
    <sourceDirectory>src/main</sourceDirectory>
    <testSourceDirectory>src/test</testSourceDirectory>
</build>
</project>

Let’s save the file in top level project directory and run analysis command from there:

smarek@14:~/apps/vfsStream$ mvn sonar:sonar
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'sonar'.
[INFO] Ignoring available plugin update: 2.0-beta-1 as it requires Maven version 3.0
[INFO] ------------------------------------------------------------------------
[INFO] Building vfsStream
[INFO]    task-segment: [sonar:sonar] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [sonar:sonar {execution: default-cli}]
[INFO] Sonar host: http://localhost:9000
[INFO] Sonar version: 2.1.2
[INFO] Execute: org.codehaus.sonar.runtime:sonar-core-maven-plugin:20101122103356:internal
[INFO] [sonar-core:internal {execution: default-internal}]
[INFO]  Database dialect class org.sonar.api.database.dialect.MySql
[INFO]  -------------  Analyzing vfsStream
[INFO]  Selected quality profile : Default Php Profile, language=php
[INFO]  Configure maven plugins...
[INFO]  Sensor PhpSourceImporter[getLanguage()=PHP,getClass()=class org.sonar.plugins.php.core.sensors.PhpSourceImporter]...
[INFO]  Importing files from project vfsStream
[INFO]  main
[INFO]  test
[INFO]  Sensor PhpSourceImporter[getLanguage()=PHP,getClass()=class org.sonar.plugins.php.core.sensors.PhpSourceImporter] done: 409 ms
[INFO]  Sensor AsynchronousMeasuresSensor...
[INFO]  Sensor AsynchronousMeasuresSensor done: 20 ms
[INFO]  Sensor PhpCodesnifferSensor...
[INFO]  ExecutePHPCodeSniffer with command 'sqlics --report-file=/Users/smarek/apps/vfsStream/build/logs/codesniffer.xml --report=checkstyle --level=warning --standard=GN --extensions=php,php3,php4,php5,phtml,inc /Users/smarek/apps/vfsStream/src/main'
[INFO]  PHPCodeSniffer ended with returned code '1'.
[INFO]  Analysing project with file:/Users/smarek/apps/vfsStream/build/logs/codesniffer.xml
[INFO]  Sensor PhpCodesnifferSensor done: 4233 ms
[INFO]  Sensor SurefireSensor...
[INFO]  parsing /Users/smarek/apps/vfsStream/build/surefire-reports
[INFO]  Sensor SurefireSensor done: 2 ms
[INFO]  Sensor CpdSensor...
[INFO]  Sensor CpdSensor done: 228 ms
[INFO]  Sensor PhpUnitSensor...
[INFO]  Parsing file :
[INFO]  Parsing file : {0}
[INFO]  Sensor PhpUnitSensor done: 637 ms
[INFO]  Sensor ProfileSensor...
[INFO]  Sensor ProfileSensor done: 13 ms
[INFO]  Sensor ProjectLinksSensor...
[INFO]  Sensor ProjectLinksSensor done: 6 ms
[INFO]  Sensor VersionEventsSensor...
[INFO]  Sensor VersionEventsSensor done: 9 ms
[INFO]  Sensor PHP Depend Sensor...
[INFO]  Collecting measures...
[INFO]  Saving measures...
[INFO]  Sensor PHP Depend Sensor done: 173 ms
[INFO]  Sensor Maven dependencies...
[INFO]  Sensor Maven dependencies done: 7 ms
[INFO]  Execute decorators...
[INFO]  ANALYSIS SUCCESSFUL, you can browse http://localhost:9000
[INFO]  Database optimization...
[INFO]  Database optimization done: 83 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 19 seconds
[INFO] Finished at: Mon Nov 22 10:34:50 GMT 2010
[INFO] Final Memory: 25M/81M
[INFO] ------------------------------------------------------------------------

Let’s get back to the browser now and refresh the dashboard.

sonar-vfsStream

Sonar dashboard after running analysis

vfsStream-dashboard

vfsStream analysis details

Congratulations! You have just analysed your first PHP project with Sonar!

Understanding the measures

I will only briefly tell you about different sections of the dashboard this time. Feel free to explore it and remember – there is quite comprehensive documentation at http://www.sonarsource.org/ including wiki, tutorials and even some screencasts!

At the top of the dashboard you have all the results of static code analysis, including all sort of statistics about your code complexity and size.

code-complexity

Code complexity analysis

On the right side of the dashboard, Sonar reports all rules violations generated by PHP_CodeSniffer. Don’t be surprised with the results you see. Remember we didn’t configure the plugin to use any specific standard. 0.2 version of the plugin uses an included GN standard, just for illustration purposes. That will definitely improve in future plugin versions and complete integration with PHP_CodeSniffer 1.3.

rules-violations

Rules violations based on PHP_CodeSniffer report

And finally at the bottom you have got results of the test suite run:

unittest-results

Unit tests results

phpUnderControl integration

Integration with phpUnderControl is really trivial. All you have to do is to add another task to your ant build file and execute it at the end of the build!

<project default="build" basedir=".">

    <!--
    All the other targets here
    -->

    <target name="sonar">
        <exec dir="${basedir}/Source/" executable="mvn" failonerror="false" >
           <arg line="sonar:sonar" />
        </exec>
    </target>

    <target name="build" depends="clean,checkout-code,update-branches,generate-configs,php-documentor,php-codesniffer,php-depend,phpunit,sonar" />

</project>

What’s next?

Version 0.3 of the plugin is coming soon to your houses soon, and with it comes:
  • better integration with PHP_CodeSniffer 1.3 (SQLi CodeSniffer no longer required)
  • rulesets support – import/export feature
  • Copy/Paste detector support (phpcpd)
  • better code coverage analysis
  • one plugin – one jar – easier installation
It will only get better! Happy analysis!

Integrate PHP_Depend with phpUnderControl

The newest version of phpUnderControl has now basic support for PHP_Depend. With PHPUnit deprecating support for metrics, it’s just about the time to switch. And it’s not as complicated as it might sound.

First of all you need to install PHP_Depend. Using pear it’s the easiest and quickest way to do it. If you haven’t registered PHP_Depend pear channel yet, it is time to do it now:

141:~ sebmarek$ sudo pear channel-discover pear.pdepend.org
Adding Channel "pear.pdepend.org" succeeded
Discovery of channel "pear.pdepend.org" succeeded

After that simply use pear to install the latest version of PHP_Depend:

141:~ sebmarek$ sudo pear install pdepend/PHP_Depend-beta
Did not download optional dependencies: pecl/imagick, use --alldeps to download automatically
pdepend/PHP_Depend can optionally use package "pecl/imagick" (version >= 2.2.0b2)
downloading PHP_Depend-0.9.11.tgz ...
Starting to download PHP_Depend-0.9.11.tgz (323,787 bytes)
..................................................................done: 323,787 bytes
install ok: channel://pear.pdepend.org/PHP_Depend-0.9.11

and confirm that PHP_Depend installed successfully:

141:~ sebmarek$ pdepend --version
PHP_Depend 0.9.11 by Manuel Pichler

The next step is to modify your project’s build file. If you don’t use phpunit configuration xml file the change is really simple. Just remove –log-metrics option from your phpunit ant task:

<target name="phpunit">
    <exec dir="/pth/to/your/module" executable="phpunit" failonerror="true">
        <arg line="--log-junit ${basedir}/build/logs/phpunit.xml
                   --log-metrics ${basedir}/build/logs/phpunit.metrics.xml
                   --coverage-xml ${basedir}/build/logs/phpunit.coverage.xml
                   --coverage-html ${basedir}/build/coverage" />
    </exec>
</target>

If you use phpunit xml file remove relevant entry from logging section:

<logging>
    <log type="coverage-html" target="/path/to/build/coverage/" charset="UTF-8" yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/>
    <log type="coverage-clover" target="/path/to/build/logs/phpunit.coverage.xml"/>
    <log type="junit" target="/path/to/build/logs/phpunit.test.xml" logIncompleteSkipped="true"/>
    <log type="metrics-xml" target="/path/to/build/logs/metrics.xml"/>
</logging>

Finally just add new ant task in the build file that will run pdepend and generate metrics xml file and additional graphs.

<target name="php-depend">
    <exec executable="pdepend" dir="${basedir}/Source" logerror="on">
        <arg line="--phpunit-xml=${basedir}/build/logs/pdepend.xml
                   --jdepend-chart=${basedir}/build/graph/08-dependencies.svg
                   --overview-pyramid=${basedir}/build/graph/09-software-metrics-pyramid.svg
                   . " />
    </exec>
</target>

<target name="phpunit">
    <exec dir="${basedir}/Source/Test/" executable="phpunit" failonerror="true" />
</target>

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

Now either wait until next build happens or simply trigger the next build manually and navigate to the metrics tab. All the charts should be still there. In addition two additional charts has been added – Package Dependencies and visual summary of the analyzed project source code.

PHP_Depend metrics

Additional charts generated with PHP_Depend

Package dependencies chart is also shown at the top of phpUnderControl Overview tab.

To learn more about software metric and PHP_Depend itself have a look at Documentation section at http://www.pdepend.org/