Tuesday, 12 August 2008

PHPUnit - issues with static method calls

Recently ran into a couple of issues concerning stubbing of static method calls when using PHPUnit.

Taking the following code snippet:

  1. <?php
  2. class Example
  3. {
  4. public function methodCall()
  5. {
  6. Logger::logMessage('message', 4, new Exception());
  7. return true;
  8. }
  9. }
  10. ?>


A static method call, which needs to be stubbed out, is made from within the methodCall() function. Mike Lively suggests refactoring under these circumstances, so that calls to static methods that are external to the class are encapsulated within a new class method.

Refactoring, then yields something like this:

  1. <?php
  2. class Example
  3. {
  4. public function methodCall()
  5. {
  6. $this->logMessage('message', 4, new Exception());
  7. return true;
  8. }
  9. public function logMessage($message, $priority, Exception $exception)
  10. {
  11. Logger::logMessage($message, $priority, $exception);
  12. }
  13. }
  14. ?>


A unit test which stubs out the logMessage() function can then be created:

  1. <?php
  2. require_once 'PHPUnit/Framework/TestCase.php';
  3. require_once 'Example.php';
  4. require_once 'Logger.php';
  5.  
  6. class ExampleTest extends PHPUnit_Framework_TestCase
  7. {
  8. public function testMethodCall()
  9. {
  10. $example = $this->getMock('Example', array('logMessage'));
  11. $example->expects($this->any())->method('logMessage');
  12. $this->assertEquals($example->methodCall(), true);
  13. }
  14. }
  15. ?>


At this point, everything works as expected.

However, problems arise if an equivalent process is followed for static method calls. For instance, if the Example class methods are static:

  1. <?php
  2. class Example
  3. {
  4. public static function methodCall()
  5. {
  6. self::logMessage('message', 4, new Exception());
  7. return true;
  8. }
  9. public static function logMessage($message, $priority, Exception $exception)
  10. {
  11. Logger::logMessage($message, $priority, $exception);
  12. }
  13. }
  14. ?>


The unit test now ignores the stubbed method and calls the original class method. Furthermore, direct calls to the stubbed method throw the following error "Fatal error: Using $this when not in object context in......."

These issues have been documented, but were not easy to find and another ticket on the PHPUnit site indicates that stubbing static methods works as expected. As can be seen when reading through the posts on ticket 139, it appears that support for stubbing static methods was withdrawn sometime between Jun 2007 and Feb 2008, with no indication that this will be made available.


No comments: