Stubbing and Mocking Static Methods

Sebastian Bergmann » 12 February 2010 » in New Features » 5 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: , ,

Trackback specific URI for this entry

5 Comments to "Stubbing and Mocking Static Methods"

Display comments as (Linear | Threaded)
  1. Daniel O'Connor
    12/02/2010 at 10:55 Permalink
    I'm worried: a series of posts which explain how to overcome obstacles in unit testing which shouldn't be there in the first place - this feels like you are being way too kind.

    I understand there can be things outside of your control, but in this day and age... Call me narrow minded, but things which hurt testability should be swept into a corner and quietly suffocated in their own global state.

    Sebastian, would you mind elaborating on why you are being so accommodating? IE you seem to be investing a fair amount of time into making the hard/crap to test code of the world a bit more testable, but in the long run "approving" it.

    Reply

  2. Sebastian Bergmann
    13/02/2010 at 06:40 Permalink
    In my work as a consultant I am often confronted with large legacy code bases that have no tests. The only (sensible) way to start getting these "under test" is to find workarounds for untestable code.

    Reply

  3. Zilvinas
    12/02/2010 at 13:30 Permalink
    Great news. It's best to avoid having static methods but sometimes you may inherit code that has them. Good to know that now it will be possible to test these methods.

    Reply

  4. Giorgio Sironi
    12/02/2010 at 17:42 Permalink
    Zilvinas, you mayy wrap in an object every external code that uses static methods. :)

    Reply

  5. Mike Hedman
    21/01/2011 at 00:04 Permalink
    I've just found that there are Windows binaries here:
    http://downloads.php.net/pierre/
    Mike

    Reply

7 Trackbacks to "Stubbing and Mocking Static Methods"

  1. www.websdeveloper.com 15/02/2010 at 20:01
  2. www.websdeveloper.com 15/02/2010 at 20:02
  3. Sebastian Bergmann 16/02/2010 at 08:20
    This article is part of a series on testing untestable code: Testing private methods Testing code that uses singletons Stubbing static methods Stubbing hard-coded dependencies In a unit test, mock objects can simulate the behavior of complex, real
  4. Sebastian Bergmann 16/02/2010 at 08:21
    This article is part of a series on testing untestable code: Testing private methods Testing code that uses singletons Stubbing static methods Stubbing hard-coded dependencies With PHPUnit 3.5 it will be possible to stub and mock static methods. C
  5. Sebastian Bergmann 16/02/2010 at 08:21
    This article is part of a series on testing untestable code: Testing private methods Testing code that uses singletons Stubbing static methods Stubbing hard-coded dependencies I frequently quote Miško Hevery with "It is hard to test code that uses
  6. Sebastian Bergmann 16/02/2010 at 08:21
    This article is part of a series on testing untestable code: Testing private methods Testing code that uses singletons Stubbing static methods Stubbing hard-coded dependencies No, not those privates. If you need help with those, this book might hel
  7. www.phparch.com 04/03/2010 at 13:13

Add Comment


To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Submitted comments will be subject to moderation before being displayed.