Using mock objects in PHP inside functions that instantiate their own objects Using mock objects in PHP inside functions that instantiate their own objects database database

Using mock objects in PHP inside functions that instantiate their own objects


Just to add on to @Ezku answer (+1, all what i would have said too) to final code could look something like this (using Dependency injection)

public function __construct(Memcached $mem, DatabaseObject $db) {    $this->mem = $mem;    $this->db = $db;}public function getSomeData() {    $key = "SomeMemcacheKey";    $cache = $this->mem;    $results = $cache->get($key);    if (!$results) {        $database = $this->db;        $sql = "SELECT * from someDatabase.someTable";        $results = $database->query($sql);        $cache->set($key, $results);    }    return $results;}

With that it is really easy to create the mock objects and pass them into the code.

There are several reasons why you could want to do this (apart from creating testable code). For once it makes your code much more open to change (want different db? pass in a different db object instead of changeing the code in your DatabaseObject.

This Blog post tells you about why static methods are bad but using the "new" operator in your code is pretty much the same thing than saying $x = StaticStuff::getObject(); so it applies here too.

Another reference can be: Why singletons are bad for testable code because it touches on the same points.

If you already have some more code written there are some ways to work those idea in without changeing everything at once.

Optional dependency injection like this:

public function __construct(Memcached $mem = null, DatabaseObject $db = null) {    if($mem === null) { $mem = new DefaultCacheStuff(); }    if($db === null) { $db = new DefaultDbStuff(); }    $this->mem = $mem;    $this->db = $db;}public function getSomeData() {    $key = "SomeMemcacheKey";    $cache = $this->mem;    $results = $cache->get($key);    if (!$results) {        $database = $this->db;        $sql = "SELECT * from someDatabase.someTable";        $results = $database->query($sql);        $cache->set($key, $results);    }    return $results;}

or using "setter injection":

public function __construct(Memcached $mem = null, DatabaseObject $db = null) {    $this->mem = new DefaultCacheStuff();    $this->db = new DefaultDbStuff();}public function setDatabaseObject(DatabaseObject $db) {     $this->db = $db;}public function setDatabaseObject(Memcached $mem) {     $this->mem = $mem;}public function getSomeData() {    $key = "SomeMemcacheKey";    $cache = $this->mem;    $results = $cache->get($key);    if (!$results) {        $database = $this->db;        $sql = "SELECT * from someDatabase.someTable";        $results = $database->query($sql);        $cache->set($key, $results);    }    return $results;}

Additional there are things called dependency injection containers that allow you to put all your objection creating away and pull everything out of that container, but since it makes testing a bit harder (imho) and it only helps you if done really well i wouldn't suggest starting with one but just using normal "dependency injection" to create testable code.


This doesn't leave much room for functions which instantiate their own database objects.

Precisely so. You're describing a style of programming that is considered one to avoid precisely because it leads into untestable code. If your code explicitly depends on some externalities and does not in any way abstract over them, you're only going to be able to test that code with those externalities intact. As you say, you can't mock things that functions create for themselves.

To make your code testable, it's preferable to apply dependency injection: pass the dependencies you wish to be mockable into the unit's context from the outside. This is usually seen as resulting in better class design in the first place.

That said, there are some things you can do to enable mockability without explicit injection: using PHPUnit's mock object facilities, you can override methods even in the unit under test. Consider a refactoring like this.

public function getSomeData() {    $key = "SomeMemcacheKey";    $cache = $this->getMemcache();    $results = $cache->get($key);    if (!$results) {        $database = $this->getDatabaseObject();        $sql = "SELECT * from someDatabase.someTable";        $results = $database->query($sql);        $cache->set($key, $results);    }    return $results;}public function getMemcache() {    return get_memcache();}public function getDatabaseObject() {    return new DatabaseObject();}

Now, if you're testing getSomeData(), you can mock out getMemcache() and getDatabaseObject(). The next refactoring step would be to inject the memcache and database objects into the class so that it would have no explicit dependencies on get_memcache() or the DatabaseObject class. This would obviate the need for mocking methods in the unit under test itself.


In a perfect world, you'd have the time to refactor all your legacy code to use dependency injection or something similar. But in the real world, you often have to deal the hand you've been dealt.

Sebastian Bergmann, the author of PHPUnit, wrote a test helpers extension that allows you to override the new operator with a callback and rename functions. These will allow you to monkey patch your code during testing until you can refactor it to be more testable. Granted, the more tests you write using this, the more work you'll have undoing it.

Note: the Test-Helper extension is superseded by https://github.com/krakjoe/uopz