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: , , ,

Testing Your Privates

Sebastian Bergmann » 09 February 2010 » in Articles » 15 Comments

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

No, not those privates. If you need help with those, this book might help.

One question I get over and over again when talking about Unit Testing is this:

"How do I test the private attributes and methods of my objects?"

Lets assume we have a class Foo:

<?php
class Foo
{
    private $bar = 'baz';
 
    public function doSomething()
    {
        return $this->bar = $this->doSomethingPrivate();
    }
 
    private function doSomethingPrivate()
    {
        return 'blah';
    }
}
?>

Before we explore how protected and private attributes and methods can be tested directly, lets have a look at how they can be tested indirectly.

The following test calls the testDoSomething() method which in turn calls the doSomethingPrivate() method:

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @covers Foo::doSomething
     * @covers Foo::doSomethingPrivate
     */
    public function testDoSomething()
    {
        $foo = new Foo;
        $this->assertEquals('blah', $foo->doSomething());
    }
}
?>

The test above assumes that testDoSomething() only works correctly when testDoSomethingPrivate() works correctly. This means that we have indirectly tested testDoSomethingPrivate(). The problem with this approach is that when the test fails we do not know directly where the root cause for the failure is. It could be in either testDoSomething() or testDoSomethingPrivate(). This makes the test less valuable.

PHPUnit supports reading protected and private attributes through the PHPUnit_Framework_Assert::readAttribute() method. Convenience wrappers such as PHPUnit_Framework_TestCase::assertAttributeEquals() exist to express assertions on protected and private attributes:

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
    public function testPrivateAttribute()
    {
        $this->assertAttributeEquals(
          'baz',  /* expected value */
          'bar',  /* attribute name */
          new Foo /* object         */
        );
    }
}
?>

PHP 5.3.2 introduces the ReflectionMethod::setAccessible() method to allow the invocation of protected and private methods through the Reflection API:

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @covers Foo::doSomethingPrivate
     */
    public function testPrivateMethod()
    {
        $method = new ReflectionMethod(
          'Foo', 'doSomethingPrivate'
        );
 
        $method->setAccessible(TRUE);
 
        $this->assertEquals(
          'blah', $method->invoke(new Foo)
        );
    }
}
?>

In the test above we directly test testDoSomethingPrivate(). When it fails we immediately know where to look for the root cause.

I agree with Dave Thomas and Andy Hunt, who write in their book "Pragmatic Unit Testing":

"In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out."

So: Just because the testing of protected and private attributes and methods is possible does not mean that this is a "good thing".

Defined tags for this entry: , ,

CRAP in PHPUnit 3.5

Sebastian Bergmann » 12 January 2010 » in New Features » 6 Comments

For the upcoming PHPUnit 3.5, I have factored out all code that is related to code coverage and put it into a separate component: PHP_CodeCoverage.

PHP_CodeCoverage is a component that provides collection, processing, and rendering functionality for PHP code coverage information. It makes PHPUnit's mature code coverage functionality available outside of PHPUnit.

Having all code that deals with code coverage in a separate component allows for easier development and better testing. The first result of these improved development conditions is a small new feature that I recently implemented, the support for the CRAP metric.

From crap4j.org:

The CRAP (Change Risk Analysis and Predictions) software metric [has] a mildly offensive metric name [and helps] to help protect you from truly offensive code.

The CRAP metric combines cyclomatic complexity and code coverage from automated tests (e.g. [PHPUnit] tests) to help you identify code that might be particularly difficult to understand, test, or maintain — the kind of code that makes developers say: “This is crap!” or, if they are stuck maintaining it, “Oh, crap!”.

The screenshot below shows how the CRAP metric is reported in the HTML code coverage report:

Code Coverage Report
Defined tags for this entry: , ,

Quality Assurance Tools for PHP

Sebastian Bergmann » 15 March 2009 » in Articles » 21 Comments

Map of PHP QA Tools

The map above contains the following tools that are useful for quality assurance in PHP projects:

  • PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.
  • phpmd scans PHP source code and looks for potential problems such as possible bugs, suboptimal code or overcomplicated expressions.
  • phpcpd is a Copy/Paste Detector (CPD) for PHP code.
  • PHP_Depend is a PHP software metrics tool.
  • PHPUnit is the de-facto standard unit test framework for PHP.

Build Automation is the act of scripting or automating a wide variety of tasks that a software developer will do in their day-to-day activities, including tasks that involve the tools listed above.

Apache Ant is a Java-based build tool that is similar to make, but without make's wrinkles. Its build files are XML-based, calling out a target tree where various tasks get executed.

The listing below shows an Apache Ant build file for a project named Money.

<project name="Money" default="build">
 <target name="clean">
  <delete dir="${basedir}/build"/>
 </target>

 <target name="prepare">
  <mkdir dir="${basedir}/build/logs"/>
 </target>

 <target name="phpcs">
  <exec dir="${basedir}"
        executable="phpcs"
        output="${basedir}/build/logs/checkstyle.xml"
        failonerror="false">
   <arg line="--report=checkstyle ."/>
  </exec>
 </target>

 <target name="phpmd">
  <exec dir="${basedir}"
        executable="phpmd"
        failonerror="false">
   <arg line=". xml codesize
              --reportfile ${basedir}/build/logs/pmd.xml"/>
  </exec>
 </target>

 <target name="phpcpd">
  <exec dir="${basedir}"
        executable="phpcpd"
        failonerror="false">
   <arg line="--log-pmd=${basedir}/build/logs/pmd-cpd.xml ."/>
  </exec>
 </target>

 <target name="pdepend">
  <exec dir="${basedir}"
        executable="pdepend"
        failonerror="false">
   <arg line="--jdepend-xml=${basedir}/build/logs/jdepend.xml ."/>
  </exec>
 </target>

 <target name="phpunit">
  <exec dir="${basedir}"
        executable="phpunit"
        failonerror="true">
   <arg line="--log-xml         ${basedir}/build/logs/junit.xml
              --coverage-clover ${basedir}/build/logs/clover.xml
              MoneyTest"/>
  </exec>
 </target>

 <target name="build"
         depends="clean,prepare,phpcs,phpmd,phpcpd,pdepend,phpunit"/>
</project>

The main target, build, depends on the targets that

  1. Delete the build directory, if it exists.
  2. Prepare the build directory, if it does not exist.
  3. Run PHP_CodeSniffer on the project's sourcecode and write a logfile in Checkstyle XML format.
  4. Run phpmd on the project's sourcecode and write a logfile in PMD XML format.
  5. Run phpcpd on the project's sourcecode and write a logfile in PMD-CPD XML format.
  6. Run PHP_Depend on the project's sourcecode and write a logfile in JDepend XML format.
  7. Run the project's tests using PHPUnit and write logfiles in JUnit XML and Clover XML format.

Below is the output for invoking Apache Ant in the project directory:

sb@ubuntu Money % ant
Buildfile: build.xml

clean:
   [delete] Deleting directory /home/sb/Money/build

prepare:
    [mkdir] Created dir: /home/sb/Money/build/logs

phpcs:

phpmd:

phpcpd:
     [exec] phpcpd 1.1.0 by Sebastian Bergmann.
     [exec] 
     [exec] 0.00% duplicated lines out of 722 total lines of code.

pdepend:
     [exec] PHP_Depend 0.9.4 by Manuel Pichler
     [exec] 
     [exec] Executing Dependency-Analyzer:
     [exec]                                                                 16
     [exec] 
     [exec] Generating pdepend log files, this may take a moment.

phpunit:
     [exec] PHPUnit 3.4.0 by Sebastian Bergmann.
     [exec] 
     [exec] ......................
     [exec] 
     [exec] Time: 0 seconds
     [exec] 
     [exec] OK (22 tests, 34 assertions)
     [exec] 
     [exec] Writing code coverage data to XML file, this may take a moment.

build:

BUILD SUCCESSFUL
Total time: 4 seconds

The generated logfiles can be processed by CruiseControl because it already knows the XML formats used. phpUnderControl is a customization of CruiseControl that caters to the needs of PHP projects and makes a lot of things easier.

Sonar enables to collect, analyze and report metrics on source code. It not only offers consolidated reporting on and across projects throughout time, but it becomes the central place to manage code quality. The developers of Sonar are working on out-of-the-box support for PHP projects.