Filina Consulting

Testing Methods That Make Static Calls

January 13th, 2016

I had trouble testing a particularly painful codebase. It had static calls and implicit dependencies all over the place, to name just a few problems.

One of the things that it often did was to call static methods that would increment counters in the database and cache stuff. Example:

 It was making things difficult.

To avoid messing with the original codebase too much, I came up with this quick and dirty way to ignore those dependencies. In my unit test, I'd write 

  and then make all static calls on it to return null:

public function mockStaticDependency($className)
    eval('class '.$className.' { public static function __callStatic($name, $arguments) { return null; } }');

It's like overloading the class with a dummy catch-all method. Yes, I know, eval is EVIL.

I think that it would be quite simple to expand this with an array of method names and their output, in case those pesky dependencies return something the Method Under Test needs. But that's for another day.

I just wanted to throw it out there, since I saw many questions on this topic without satisfying answers. I know that dealing legacy code is hard enough without testability problems.

Update 2016-01-16

As per the suggestion in the comments, I tried Patchwork. It was brilliant! Not only does it avoid issues when repeatedly mocking the same class, it allows you to easily mock specific methods and provide any implementation, like returning test data. Here is how to do the same as above with Patchwork:

Patchwork\replace('Record::incrementViews', function() {
    return null;

Regarding adding an implementation, say we have a method 

. We can use Patchwork to return the data we need.

Patchwork\replace('Record::findById', function($id) {
    return array('id'=>$id, 'name'=>'Anna');

In short, Patchwork is really the way to go to test untestable code.


Gundars January 13th, 2016 Not only it's evil, it's also mostly disabled, but this still is better than most answers in the subject
Spudley January 13th, 2016 For testing code like this, I've found the Patchwork library to be invaluable.

Patchwork basically provides monkey-patching for PHP. It makes it much easier to write good tests for a lot of the crusty code I have to work with.

Just do Patchwork\replace('Classname::method', function() { /*do nothing*/}); at the start of your test, and Patchwork\undoAll() in your teardown. Job done.
Anna January 13th, 2016 Awesome! That's exactly what I've been looking for. I'll definitely try it. I'll update the post after that.
Ben Ramsey January 25th, 2016 I thought I'd point out that you may also do the same with Mockery:

When testing in this way, you're injecting a new class with the same name. If using an autoloader, and the real version of the class gets loaded first in a different test, you'll encounter errors (also true if your eval'd version gets loaded first and a later test expects the real class). So, you'll need to run your tests in isolation. You can do this with PHPUnit annotations "@runInSeparateProcess" and "@preserveGlobalState disabled". This method of testing is impossible to use if using "require/include" to include files, rather than an autoloader.

I gave a recent talk on this, where I showed some examples:

And I wrote an article showing how to test hard dependencies (use of the "new" keyword inside a unit) using mock instances:

Obviously, these kinds of tests aren't ideal and there are ways to refactor around this, but it's great to know we have options for testing legacy code without having to do full rewrites.

This page is protected by reCAPTCHA and the Google
Privacy Policy and Terms of Service apply.

Twitter: @afilina | E-mail: