Using HipHop for Static Analysis

Sebastian Bergmann » 27 July 2010 » in Articles » 0 Comments

HipHop for PHP, the source code transformer that turns PHP code into C++ code that can then be compiled with g++, can also be used for static code analysis to find problems in PHP source code.

sb@vmware Money % hphp -t analyze --input-dir .
running hphp...
creating temporary directory /tmp/hphp_Zz7AXg ...
parsing inputs...
parsing inputs took 0'00" (20 ms) wall time
inferring types...
inferring types took 0'00" (10 ms) wall time
saving code errors, dependency graph and stats...
all files saved in /tmp/hphp_Zz7AXg ...
running hphp took 0'00" (208 ms) wall time

The script below takes a CodeErrors.js file (which is generated by hphp and in the example above is saved to /tmp/hphp_Zz7AXg) as its input and print an XML document in Checkstyle's format (the same XML format that is also used by PHP_CodeSniffer, for instance). This XML logfile can then be used with Hudson, for instance, in a continuous integration context.

Defined tags for this entry: , ,

thePHP.cc at IPC:SE 2010

Sebastian Bergmann » 26 May 2010 » in Events » 2 Comments

thePHP.cc - The PHP Consulting Company

thePHP.cc - The PHP Consulting Company will present the following workshops and sessions at this year's International PHP Conference: Spring Edition in Berlin:

Continuous Inspection and Integration of PHP Projects

Sebastian Bergmann, 30.05.2010, 09:15 - 13:00, Room: Salon 4

Continuous Integration with automated code analysis and test execution has seen broad adoption in recent years. The ideas behind this have changed how companies look at Build Management, Release Management, Deployment Automation, and Test Orchestration. This session presents the best practices and available tools that provide an insight into the development progress and code quality.

The Cake is a Lie

Sebastian Bergmann, 31.05.2010, 09:15 - 10:15, Room: Salon 6

Even if you have not played the game "Portal" you might have come across the phrase "The cake is a lie". According to the Urban Dictionary, it roughly translates to "your promised reward is merely a fictitious motivator". Scaffolding, the meta-programming method of building software applications, promises easier development and a faster time-to-market. But the "code generation bliss" can lead to problems later on, for instance with regard to maintainability and scalability. This session takes a sceptical look at frameworks such as CakePHP and Symfony.

Building a PHP Preprocessor with Plain PHP

Arne Blankerts, 31.05.2010, 15:15 - 16:15, Room: Salon 6

Ever wished to have a preprocessor for PHP? Now you can! In this session we will implement a simple yet powerful preprocessor using the streamwrapper technology that works out of the box on any PHP installation. This opens up a whole new world of possibilities like annotation parsing, AOP, or dependency resolution in PHP development - all transparently done in the background.

Continuous Integration and Unit Testing in Agile Environments

Sebastian Bergmann, 01.06.2010, 16:00 - 17:00, Room: Salon 7

As part of the Agile Day, this session will shine a light on the roles that Continuous Integration and Unit Testing play in agile environments.

Diapers: When They Smell, Change Them

Stefan Priebsch, 30.05.2010 - 02.06.2010, Room: $HOME

Stefan Priebsch can not join us this year for the International PHP Conference: Spring Edition in Berlin. Earlier this month he became the proud father of two beautiful twins, Lara and Patrick. We hope that he will be at the International PHP Conference this fall in Mainz.

Arne and I are looking forward to see you in Berlin next week!

Defined tags for this entry: ,

Code Coverage Dashboard

Sebastian Bergmann » 03 April 2010 » in Announcements » 2 Comments

Almost a year ago I started to factor out all the code that deals with code coverage in PHPUnit and put it into a separate component. The name of this component is PHP_CodeCoverage.

PHP_CodeCoverage is a library that provides collection, processing, and rendering functionality for PHP code coverage information. Its architecture has support for multiple backends for collecting code coverage information (currently only support for Xdebug is implemented) and for reporting code coverage information (for instance using Clover XML or as an HTML report).

As mentioned earlier, the HTML report that is generated by PHP_CodeCoverage shows the CRAP Index software metric for each function or method. Today I built on this earlier development and added a "dashboard view" to the HTML report that shows the following software metrics:

  • Class Coverage Distribution: This is a bar chart that shows how many classes have 0%, ..., 100% code coverage
  • Class Complexity: This is a scatter chart that shows the coverage (X axis) and the complexity (Y axis) of the classes
  • Top Project Risks: This is list of the classes with the highest CRAP Index
  • Least Tested Methods: This is the list of the least tested methods

You can see an example of the dashboard view below:

PHP_CodeCoverage Dashboard View
Defined tags for this entry: , ,

Stubbing and Mocking Static Methods

Sebastian Bergmann » 12 February 2010 » in New Features » 4 Comments

This article is part of a series on testing untestable code:

With PHPUnit 3.5 it will be possible to stub and mock static methods.

Consider the class Foo:

<?php
class Foo
{
    public static function doSomething()
    {
        return static::helper();
    }
 
    public static function helper()
    {
        return 'foo';
    }
}
?>

When testing Foo::doSomething() we want to decouple it from its dependency Foo::helper(). With PHPUnit 3.5 and PHP 5.3 as well as consistent use of late static binding (using static:: instead of self::) the following is possible:

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
    public function testDoSomething()
    {
        $class = $this->getMockClass(
          'Foo',          /* name of class to mock     */
          array('helper') /* list of methods to mock   */
        );
 
        $class::staticExpects($this->any())
              ->method('helper')
              ->will($this->returnValue('bar'));
 
        $this->assertEquals(
          'bar',
          $class::doSomething()
        );
    }
}
?>

The new staticExpects() method works similar to the non-static expects() variant.

This approach only works for the stubbing and mocking of static method calls where caller and callee are in the same class. This is because static methods are death to testability:

"Unit-Testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. Seams work through polymorphism, we override/implement class/interface and then wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to override the called method dependency."
Defined tags for this entry: , ,

Testing Code That Uses Singletons

Sebastian Bergmann » 11 February 2010 » in Articles » 12 Comments

This article is part of a series on testing untestable code:

I frequently quote Miško Hevery with

"It is hard to test code that uses singletons."

And then my audience asks me ...

Why is it hard to test code that uses singletons?

Lets have a look at the default implementation of the Singleton design pattern in PHP:

<?php
class Singleton
{
    private static $uniqueInstance = NULL;
 
    protected function __construct() {}
    private final function __clone() {}
 
    public static function getInstance()
    {
        if (self::$uniqueInstance === NULL) {
            self::$uniqueInstance = new Singleton;
        }
 
        return self::$uniqueInstance;
    }
}
?>

The code above declares a class that cannot be instantiated (or cloned) by a client using the new (or clone) operator(s). To get a reference to the only instance of the class one has to use the static method getInstance(). Usually the code that uses the Singleton (which we will refer to as client) is strongly coupled to the getInstance() method:

<?php
class Client
{
    public function doSomething()
    {
        $singleton = Singleton::getInstance();
 
        // ...
    }
}
?>

It is impossible to write a test for the doSomething() method without also invoking the singleton's getInstance() method. This means that we cannot get a fresh instance of the Singleton class and thus have no guarantee that there are no side effects in multiple tests that interact with the singleton.

Dependency Injection

Dependency Injection can help with decoupling the client from the getInstance() method:

<?php
class Client
{
    public function doSomething(Singleton $singleton = NULL)
    {
        if ($singleton === NULL) {
            $singleton = Singleton::getInstance();
        }
 
        // ...
    }
}
?>

Instead of unconditionally invoking the getInstance() method inside the doSomething() we can now optionally pass in an instance of the Singleton class. This allows us to pass in a test-specific equivalent such as a mock object or stub:

<?php
class ClientTest extends PHPUnit_Framework_TestCase
{
    public function testSingleton()
    {
        $singleton = $this->getMock(
          'Singleton', /* name of class to mock     */
          array(),     /* list of methods to mock   */
          array(),     /* constructor arguments     */
          '',          /* name for mocked class     */
          FALSE        /* do not invoke constructor */
        );
 
        // ... configure $singleton ...
 
        $client = new Client;
        $client->doSomething($singleton);
 
        // ...
    }
}
?>

Alternative Singleton Implementations

Either as an alternative or in addition to rewriting the clients to optionally accept an instance of the Singleton class as an argument, we can also rewrite the Singleton class to make testing easier.

Resettable Singleton

The first approach is to add a reset() method to the Singleton class:

<?php
class Singleton
{
    private static $uniqueInstance = NULL;
 
    protected function __construct() {}
    private final function __clone() {}
 
    public static function getInstance()
    {
        if (self::$uniqueInstance === NULL) {
            self::$uniqueInstance = new Singleton;
        }
 
        return self::$uniqueInstance;
    }
 
    public static function reset() {
        self::$uniqueInstance = NULL;
    }
}
?>

Invoking the reset() method causes the getInstance() method to create a fresh object of the Singleton class the next time it is called.

Singleton with Test Context

The second approach is to add a testing context to the Singleton class:

<?php
class Singleton
{
    private static $uniqueInstance = NULL;
    public static $testing = FALSE;
 
    protected function __construct() {}
    private final function __clone() {}
 
    public static function getInstance()
    {
        if (self::$uniqueInstance === NULL ||
            self::$testing) {
            self::$uniqueInstance = new Singleton;
        }
 
        return self::$uniqueInstance;
    }
}
?>

Setting Singleton::$testing = TRUE; causes the getInstance() method to create a fresh object of the Singleton class each time it is called.

PHPUnit Can Help, Too

PHPUnit has a backup/restore mechanism for static attributes of classes.

This is yet another feature of PHPUnit that makes the testing of code that uses global state (which includes, but is not limited to, global and superglobal variables as well as static attributes of classes) easier.

Just Because You Can, Does Not Mean You Should

Yes, it is possible write testable code that uses singletons.
This does not mean, however, that you should use them without thinking twice.

Defined tags for this entry: , , ,