gcb
gcb

Reputation: 14548

best way to mock a global static method

my application has a logger library with the signature:

final class Logger {
  public static method debug($msg);
  public static method warn($msg);
  public static method error($msg);
}

the class i want to test, another global static helper, use it as

final class TestMe {
  public static method TestThis(){
    Logger::debug('TestThis() called');
    doThings();
  }
}

How to test the TestMe class by mocking the Logger one and waiting for the expected messages?

Upvotes: 1

Views: 4593

Answers (2)

Schleis
Schleis

Reputation: 43700

Your Logger class cannot be mocked by PHPUnit for a couple of reasons.

  1. The class is listed as final which means that it cannot be extended. When PHPUnit creates a mock of an object, it creates a new object that extends the class being mocked. The final keyword prevents extending a class, so a mock cannot be created.
  2. The methods that you want to replace are being called statically. You are not able to replace them because the calls are being directed to the actual class. PHPUnit 5.3 has a way of "mocking" static methods but that is only within the class being called statically. It doesn't replace calls from outside of the class.

http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/

You have two options for testing things like this:

  1. Increase the scope of the behavior that you are testing. Assert that whatever the Logger class is doing gets done. This will make any tests less of a "unit" test but they do encapsulate the behavior that is expected and can still be useful.
  2. Refactor your usages to use dependency injection, so that you can pass in a mockLogger that doesn't call the methods statically. This may be more painful but will result in your code more flexible IMO.

Upvotes: 4

alfallouji
alfallouji

Reputation: 1170

If you are using a testing framework like PHPUnit, it offers the ability to mock an object. You could create a mock object for your logger class and define the debug method in it.

It is explained in details here :

https://phpunit.de/manual/current/en/test-doubles.html

Here is a little example taken from that page :

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
    public function testStub()
    {
        // Create a stub for the SomeClass class.
        $stub = $this->getMockBuilder('SomeClass')
                     ->getMock();

        // Configure the stub.
        $stub->method('doSomething')
             ->willReturn('foo');

        // Calling $stub->doSomething() will now return
        // 'foo'.
        $this->assertEquals('foo', $stub->doSomething());
    }
}
?>

Upvotes: -2

Related Questions