Extending final Classes and Methods by manipulating the AST

We know that we should always write unit tests for our code, and mock dependencies; but that isn’t always easy when we need to mock classes define as final, or that contain final methods. This isn’t normally a problem when we’re only working with classes within our own libraries and applications, because we control whether they are final or not, and we can type-hint these dependencies to interfaces. However, when the dependencies that we use are from external libraries, we lose that control; and it can become harder to test our own classes if we do need to mock final classes adn they haven’t been built to interfaces.

Libraries like Mockery do provide a proxy approach to mocking final Classes, which works well, but with one major limitation.

In a compromise between mocking functionality and type safety,
Mockery does allow creating "proxy mocks" from classes marked
final, or from classes with methods marked final. This offers
all the usual mock object goodness but the resulting mock will
not inherit the class type of the object being mocked, i.e. it
will not pass any instanceof comparison.

Unfortunately, this limitation still causes problems when passing the mock to a method with type-hinted arguments to the class rather than to an interface if we need to Dependency-inject the mock; or if we don’t have much choice because the the final class wasn’t implementing an interface. Library writers take heed if you define any of your classes as final; always write them with an interface that can be type-hinted.

So is there any way we can create a test double that matches type-hinting when we need to pass it into the class that we’re testing? I’ve been looking at an alternative approach to mocking that does allow me to create a test double that extends a final class.

Continue reading

Advertisements
Posted in PHP | Tagged , , , | Leave a comment

Closures, Anonymous Classes and an alternative approach to Test Mocking (Part 3)

I have heard people say that you shouldn’t test abstract classes or traits, only the concrete classes that implement or use them. I don’t follow that approach: unit testing is all about testing in isolation from anything that might affect those tests. Testing a concrete class that implements an abstract one, or uses a trait, means that the abstract class or trait is no longer fully isolated, but is being tested within the scope of the whole of that concrete class. We should still always test concrete classes as well; but we should also test the abstract classes and traits as individual units.

So just how do we test something that cannot be instantiated on its own?

Continue reading

Posted in PHP | Tagged , , , , , | 1 Comment

Closures, Anonymous Classes and an alternative approach to Test Mocking (Part 2)

The last time I posted here, I was writing about Anonymous Functions and how they can be bound to any object (or class) to execute as though they are a method within the scope of that class (Closure Binding as an alternative to “use” variables); and in the first article in this series, I looked at using a Closure to access private and protected properties of an object.

I was going to write this particular article about using simple Anonymous Classes to create test doubles for Unit Testing – and may well return to that topic in a future article in the series – but Matt Brunt has written a good post on that topic already, so instead I’m going to focus on a different approach to using an Anonymous Class to verify the values of object properties that we otherwise couldn’t see directly when testing a class.

Continue reading

Posted in PHP | Tagged , , , , , | 1 Comment

Closure Binding as an alternative to “use” variables

As a general rule when creating a Closure, arguments are passed when the function is called, but “use” variables (I’m sure that they have a formal name, but have no idea what it might be, so I just refer to them as “use” variables because they’re passed to the Closure through a “use” clause) are fixed as the value that they already contain when the Closure is defined, and the variables themselves must already exist within that scope. This isn’t normally a problem where we’re defining the Anonymous function inline, because we can specify the values directly in the callback function itself:


$filteredArrayData = array_filter(
    $arrayData,
    function($value) { return $value->price >= 120.00 && $value->price < 250.00; }
);

Writing our callbacks like this has the big benefit of being easy to read and understand exactly what the callback is doing.

Of course, the drawback of this approach is that when we need to change the price minimum and maximum values for filtering, they’re hard-coded in the callback.
For those array functions that use callbacks, such as array_filter(), we can’t simply pass the values as extra parameters directly to the function; although we can define the price range values as variables that can then be passed to the callback function as “use” variables. Perhaps a more practical approach than hard-coding them if we get the minimum and maximum values for filtering from user input, or if they need to be calculated elsewhere in our code.


$minimumPrice = 120.00;
$maximumPrice = 250.00;

$filteredArrayData = array_filter(
    $arrayData,
    function($value) use ($minimumPrice, $maximumPrice) {
        return $value->price >= $minimumPrice && $value->price < $maximumPrice;
    }
);

Continue reading

Posted in PHP | Tagged , , , | 14 Comments

Closures, Anonymous Classes and an alternative approach to Test Mocking (Part 1)

Since their first introduction with PHP 5.3, Closures have proven an incredibly useful feature for writing simple callback code, making it cleaner and more intuitive. Anonymous Functions can be used inline for many of the array functions


$price = 100.00;
$filteredArrayData = array_filter(
    $arrayData,
    function($value) use ($price) { return $value->price >= $price; }
);

or assigned to a variable as a Lambda that can be referenced many times in different places in your code.


$sortByField = function($valueA, $valueB) use (&$field) {
    return $valueA->$field <=> $valueB->$field;
};

$field = 'title';
usort($arrayData, $sortByField);

But this isn’t an article about the differences between Anonymous and Lambda Functions and Closures, or about whether Closures really are Closures compared to their equivalent in other languages, or about the difference between the function arguments and “use” variables, or even the significance of “pass by reference” in this example; there are other blogs that cover such topics. Instead, I want to take a look at binding Closures to objects as a first step to demonstrating an alternative approach to test mocking.

Continue reading

Posted in PHP | Tagged , , , , | 5 Comments

Heroes of PHP™ #3

Last year at Christmas I posted my original 24 Heroes of PHP™, with a second post listing a further 24 of my heroes at New Year. I’ve decided to repeat the exercise this year, although my list this time is just 11 names. All of these are people that have inspired me in some way or other in 2016.
Continue reading

Posted in PHP | 1 Comment

Musings of a PHPDiversity Rainbow Elephpant

IT’S HAPPENING! Finally, the kickstarter is happening! And I’m ecstatic.

I’d so been hoping that the kickstarter would be launched last Friday, and it felt frustrating when the day ended, and I hadn’t heard anything back from the kickstarter review team. And then I was twiddling my toes all weekend because I knew that I couldn’t do anything until the next working week; but then Monday arrived, and the kickstarter was rejected because of its potential charitable aspects. It was such a disappointment!

But Mark has since reworked it, ensuring that it conforms to all the kickstarter guidelines, and submitted it to appeal; and now I’ve had the good news from kickstarter, and the launch is happening… and I’m so happy again, because it’s the next step in my plans for world domination spreading the Diversity message throughout the worldwide PHP Community.

Promoting Diversity within the worldwide PHP Development Community regardless of race, gender, sexual orientation, gender identity, age, nationality, disability, religion and technology.

So the kickstarter campaign is about to go live, and will run until shortly before midnight on December 8th (UTC) and I’m a very happy Elephpant. Here’s the kickstarter link: please help make me a success.

Continue reading

Posted in PHP | Tagged , , | Leave a comment