PHP, Zend Framework and Other Crazy Stuff
Archive for March, 2009
Zend Framework: Survive The Deep End Update
Mar 22nd
Since the rumour mill has been active a while, I confim two chapters of the book will be released this week. Unfortunately, changing jobs remains a time consuming and distracting endeavor. I also made a commitment to finish off initial releases of several open source tools/ZF components during February/March (see MutateMe and Mockery for the first two of four being planned). To kick off a new spell of book updates, the next Chapter will be “A Simple Hello World Example”, with an Appendix titled “Virtual Hosts On Apache 2″. The following Chapter approximately one week later will be an introduction to the application to be built for most of the first half of the book.
Can we now put to death any idea the book is being shutdown/neglected/lost in space?
Unlike a published book, there is no fixed schedule and it will see delays of a month or two when life decides to interrupt me. As stated before, it will take a full year for a complete book to emerge – anyone who has written articles or books knows these things take time, patience and a ton of research. Yep, even a simple Hello World example takes its toll on my time and I hope the results are worth the wait since you should remember the whole point of this book is to not simply cover a bunch of simple examples (the RG has tons of those).
I hope the approach so far is making sense – we’re pushing the envelope in several ways of how the ZF is taught with Appendices throwing in apparently unrelated (but actually essential) accompanying information. Nginx reverse proxies? Apache virtual hosts? Next I’ll be talking static page caching since it’s one of those features I recently proposed (why it was never originally added is beyond me).
So please be patient! Not I find the impatience irritating (it’s actually quite encouraging
). The book is not my sole obsession.
The Case For Dependency Injection – Part 2
Mar 13th
The Recap
In Part 1 of this series, we briefly passed over the concept of Dependency Injection, identifying several injection strategies as below:
1. Constructor Injection
2. Setter Injection
3. Factory Design Pattern
These three patterns have been the mainstay in managing dependencies in PHP source code ever since PHP was capable of handling object oriented programming. However, these strategies can accumulate problems:
1. They require manual management of dependencies when creating new objects.
2. They require users to understand the internal workings of dependencies.
3. They clutter APIs with undocumented methods.
4. They add complexity to tests since manual injections must be performed.
5. They increase the cost of change (manual editing is needed for API changes)
6. They promote static methods in PHP (easier than creating specific objects).
This is not to say, don’t use them! In most circumstances, application of the well known strategies is not only possible but advisable. There is little benefit adding the complexity inherent in Inversion Of Control to simple scenarios.
Inversion Of Control applies to the complex, not the simple.
In isolation, none of these strategies are anything but innocent. But their combined complexity increases as your application grows and networks of classes acumulate. That’s why simple examples of Dependency Injection are doomed to failure – the problems have simple solutions. What we need is something to illustrate that Dependency Injection and Inversion Of Control are applicable to something more concrete, like a fully formed Klingon Bird Of Prey with all the bells and whistles!
[geshi lang=php]class Ship_Klingon_BirdOfPrey {
// arrays indicate multiple object instances are required
protected $warpCore = null;
protected $disruptorBanks = array();
protected $warpEngine = null;
protected $shields = array();
protected $crew = null;
protected $shipsLog = null;
protected $computer = null;
protected $sensors = array();
// …
}[/geshi]
Are you getting the picture yet?
Consider any application based on a complicated process. You may have dozens of objects working in concert towards a single goal. Kapla!
To create the client object, a Bird Of Prey, you need to inject every service object it requires since they are needed. In a simple use case, however, the user only wants a damn ship! They don’t care about the components unless they have a need to customise some internal operation. In this scenario, the Factory option might work. Using the Factory, we need to cover off on the testing piping using static means. We could just use any available setters or constructor parameters – but then our tests are going to be huge whenever a new Ship is needed.
But let’s dig deeper! How will we use the Ships Log? Every component will need to report it’s status there – so the Log is a service to the Ship, and to every other sub-system. Let’s double our Factory method length. Now, what if the computer needs to liase with the Sensors, acquire a Target via the Computer, and order the Disruptor Banks to fire? So the Sensors, Log, Disruptor Banks and possible Crew complement become needed by the Computer. Let’s double…nay…quadruple everything.
Next we decide to give the Computer a database, along with the Log, the Ship and maybe the Crew. Or we realise half this stuff are Models anyway, so give them all databases to play with!
Excuse me while I sit in a corner and cry…I only wanted a bloody ship! Why are making me do all this?
The Service Locator Pattern
Complex problems can still have simple solutions, and the Service Locator has long superceded the Factory when the going gets a bit tougher. Manually handling complex dependencies is insane (on all levels), so a little configuration can be handy.
A simple Service Locator is used like a map. If an object needs a specific service object, it refers to the Locator to retrieve a copy. You can embellish the system in any number of ways using keywords, tagging, URLs, and even utilise concrete Factories as needed, but the simplest Service Locator is a plain old array (which is also the simplest Registry):
[geshi lang=php]$locator = array(
‘log’ => new Ship_Log,
‘warpCore’ => new Ship_WarpCore,
‘computer’ => new Ship_Computer,
‘warpEngine’ => new Ship_WarpEngine,
// …
);[/geshi]
If you pass this locator to the Bird Of Prey, and let the BOP pass it to all other service objects it retrieves from the Locator array, then you can cut out the complex web of dependencies from manual management and let them all refer to the Locator instead. You can even adapt the Locator in tests to return Mock Objects. Aside from object lookup, you can also integrate configuration so the located objects can be constructed correctly.
So where are the negatives? Well, now everything needs to know about this super Service Locator, since otherwise objects couldn’t find their dependencies. It also ignores the order of creation – some objects need to be created before others or the more circular dependencies will fail to be available. If we try to create the Computer, but not the Log, then we can’t give the Computer a Log and the locator will fail. This would necessitate…manual intervention. We’d need to manually track and switch around code across numerous classes to ensure the order of creation is executed correctly. This is far from ideal, so while a Service Locator is a highly useful tool in the toolbox, orchestrating the dependency web needs something more.
The Next Obvious Evolution
As we gradually evolve from simple injection, the Service Locator was revealed as a capable, lightweight, flexible solution. It’s primary problem was dependency resolution. Rather than scatter this across all those classes, why not simply centralise them in the Service Locator itself? It’s at this point we shift from a Locator, to a simple Dependency Injection Container (ah, finally the Container term
) and leave our poor overburdened objects free of this distraction to focus solely on their roles.
Here’s an ultra simple IOC container:
[geshi lang=php]class DIContainer {
protected $_data = array();
public function set($name, $value) {
$this->data[$name] = $value;
}
public function get($name) {
if (isset($this->data[$name])) {
return $this->data[$name];
}
return $this->call(‘get’.ucfirst($name));
}
protected function getLog() {
$log = new Ship_Log($this->get(‘logfile’));
$this->data['log'] = $log;
return $log;
}
protected function getWarpCore() {
$warpCore = new Ship_WarpCore();
$this->data['warpCore'] = $warpCore;
$warpCore->setLog($this->get(‘log’));
}
protected function call($method) {
return $this->{$method}();
}
// …
}[/geshi]
This new Container class is a really simple implementation of a DI Container which assumes all client objects will utilise the exact same service objects. Like a Service Locator, you can use it to grab registered objects. However, it is written to also determine the order of creation of any object requested, then create it, and finally return it.
[geshi lang=php]$container = new DIContainer;
$container->set(‘logfile’, ‘/tmp/shiplog’);
$warpCore = $container->get(‘warpCore’);[/geshi]
A completed version could utilise the simple Strategy Pattern so you could have a single container for specific Model types accepting configuration options for everything the Container needs.
[geshi lang=php]$container = new DIContainer_Ship;
$container->set(‘type’, ‘Klingon BOP’);
$container->set(‘logfile’, ‘/tmp/shiplog’);
$container->set(‘db_type’, ‘mysql’);
$container->set(‘ship_db_table’, ‘ships’);
$container->set(‘capacity’, ’300′);
$ship = $container->get(‘ship’);[/geshi]
Of course, let’s not let this get away free
. The obvious flaw is the amount of manual programming it still needs, even though it’s drastically reduced the overall code need by avoiding code duplication and centralising this task. While the dependency management is cool, the wiring is all manual. Adding the element of automation to the new Container concept with a little Reflection and typehinting could go far. Adding cloning might speed up the creation of Containers by allowing minor configuration tweaks. Adding object replacement would allow for Mock/Stub insertion. I’m sure you can think of lots of added elements to make something easier to utilise.
Conclusion
We’ve finally met the simplest kind of IOC possible. In Part 3, we’ll move outside this simple and flawed implementation, and take a look at the forms of IOC frameworks living in the wild whether they be PHP, Python or Ruby. Frameworks should, in theory, make these Containers a lot easier to setup and maintain in a more strucured form that removes the need for customising classes. Instead mixing convention with some configuration, and taking advantage of Reflection, should produce more maintainable and testable options.
The Case For Dependency Injection – Part 1
Mar 12th
It’s been years since I first met the concept of Dependency Injection, and despite the influx of proposals, actual libraries, and spotty writing on the topic, it remains elusive in PHP. Well, with my newfound freedom to bang on my keyboard and commit real time to development and writing, I’m making this provocative and sometimes accusatory entry to perhaps spark some progress.
What is Dependency Injection?
Explaining Dependency Injection is not that hard:
[geshi lang=php]class KlingonBOP {
public $power = null;
public function __construct() {
$this->power = new WarpCore();
}
public function toWarp($factor) {
if($this->power->has($factor*10)) {
return true;
}
return false
}
}[/geshi]
This KlingonBOP class can be thought of as a client which depends on services (other objects) in order to function (the analogy is really to assist understanding the relationships), like the WarpCore object which is a service to the KlingonBOP client.
Now consider how write a unit test for this class. Unit testing works by testing classes in isolation from their dependencies – this rules out any unintended interference from other classes (i.e. a cascading set of failures), and also removes the need to actually develop the service/dependent class right now.
In the code above, we have an obvious problem – in a test, we cannot replace the WarpCore object since it is explicitly instantiated in the constructor. By replace, I mean write the tests using a Mock Object or Stub instead of a real WarpCore instance, something which has predictable constant return values.
Dependency Injection Strategies
Dependency Injection is all about how to inject these service objects into the client objects, making use of them in such a way they can be easily swapped by any other source code (not just tests!). Assuming you’re with me so far, you can identify the two most obvious Dependency Injection strategies:
1. Pass the service to the constructor as a parameter (contructor injection).
2. Pass the service to a class mutator/setter method (setter injection).
Using either of these, we can write a nice isolated unit test such as:
[geshi lang=php]require ‘Mockery/Framework.php’;
class KlingonShipTest extends PHPUnit_Framework_TestCase {
public function testAllowsWarpIfSufficientPowerAvailable() {
$ship = new KlingonBOP(
mockery(‘WarpCore_Stub’, array(‘toWarp’, ‘true’))
);
$this->assertTrue($ship->toWarp(1));
}
}[/geshi]
or
[geshi lang=php]require ‘Mockery/Framework.php’;
class KlingonShipTest extends PHPUnit_Framework_TestCase {
public function testAllowsWarpIfSufficientPowerAvailable() {
$ship = new KlingonBOP();
$ship->setWarpCore(
mockery(‘WarpCore_Stub’, array(‘toWarp’, ‘true’))
);
$this->assertTrue($ship->toWarp(1));
}
}[/geshi]
Now we can edit the class for the constructor injection or setter injection strategies as appropriate…
These two DI options are often called “Manual Dependency Injection” or “Construction By Hand”, a reference to the fact we are manually constructing and handing services to client objects. Every single service object gets the manual treatment, and that’s the norm in most PHP source code. It’s a primary underpinning of the concept of composition in OOP afterall.
So what’s the problem? It’s manual!
Anything manual has two facets. First, you need to know how to do it by hand (RTFM
). Secondly, you better do it right and add more tests. Third, it must be duplicated everywhere so you better not forget how to do it…ever!
Being manual isn’t all bad though, most objects need one, two or at most three service objects. It’s messy in large doses but quite manageable. It’s when things become unmanageable that it becomes interesting because its at that point all those fluffy ideals like unit testing and decoupling are thrown out the window (I prefer to flush mine down the drain, but everyone’s a critic).
The most likely outcome of the manual approach is the duplication of all that object wiring. What happens if the API changes? You need to manually re-edit all those instantiations and API calls across the application(s). When they break BC for the next version? Manually edit…again. The other is requiring in-depth knowledge of every detail including how internal objects are utilised. Besides adding additional onus on people to refer constantly to the manual, or far worse – the source code itself, it ignores the concept that only the outer public API has real value – the rest is just an annoying burden of knowledge weighing us down. I don’t know about other programmers, but I never bother to memorise anything but a library’s basics. Why should I? Programmers are supposed to be supported in their group laziness
.
Let’s emphasise everything so far by moving onto Dependency Injection strategy three – the Factory and Abstract Factory design patterns. You didn’t really think I forgot about them, did you?
.
Both patterns have simple goals, to centralise the creation logic of objects so they are easier to reuse, and reduce code duplication across your source code where the created objects are needed. Typically they wind up being class methods. Annoying, irksome, untestable, static class methods.
But let’s not go overboard, we can make the Factories into specific classes (they have a separate role afterall!) with public methods instead (PHP is obsessed with those bloody static methods so the trail ends there usually) which instantly makes them amenable to Dependency Injection strategies 1 and 2 (and allows you to mock/stub the factory object in tests). This does wonders, and then you find out about the punchline…
Factories add three layers of complexity, not two, so you now need to double up on Mock Objects and stubs in tests. To utilise Mock Objects in place of the dependent object (created by the Factory class for the dependee), you need a way to force the Factory to send out mocks or stubs in place of creating an actual new object. At this point you start scratching your head, so you throw in a setter which you realise won’t work (Factories don’t remember what they create, they just return the end product immediately), and perhaps toe across the line and apply the Registry pattern to make Factories hold a static memory of any mock/stub you need it to use instead of creating a new one. Sometimes you’ll simply do away with the Factory (basically accepting the cost of its loss in added complexity to the end user!) and fall back on setter/constructor injection.
We’ll assume that the tactic used is the simpler option – stub the Factory class, and set a canned response which is actually another mock/stub of the object being created. Twice the mocks, unless it’s a static method (yes, I am hating static methods way too often in this post
).
If there is such a thing a Singletonitis, Factoryitis is a close relative. A simple Factory is great, but then you realise the Factory isn’t creating one single universal object, it’s dynamically creating variations based on passed parameters, config files, or via multiple public methods for hand coded variations. That’s a lot of surrounding code, and if your original duplication varied on the inputs, a Factory buys you little benefit apart from centralising all that muck in one place where it builds up and grows into complex monolithic code blocks. And how do you even test the Factory anyway? You already tested each object it creates, so you duplicate that to maintain some sanity?
Note: You can test even static factories, once you remember to clean them up in reverse. Technically though, you still can’t mock or stub the buggers without adding test wiring – extraneous methods and properties only used by tests.
This raises a spectre of a problem – if a factory is not easily tested, and we sacrifice it to fall back on more testable injection strategies, we’re lost the benefits of the factory in reducing complexity to the end user and code duplication across the source. Can we take back control?
Dependency Injection: The Inversion Of Control
So we know the basics, inherently, without really calling them Dependency Injection outright, but Dependency Injection is also its own strategy by combining facets of all these strategies into a single comprehensive solution. Something that makes testing, composition, and configured creation easy without all the nasty consequences (well, so it claims – judge for yourself). From now on I’ll refer to this overarching strategy simply as Inversion Of Control (IOC). Often IOC is used interchangeably with DI which can be confusing, so bear in mind DI is IOC plus the original injection strategies I’ve mentioned so far.
IOC makes a few assumptions I’m already pushed around. It needs to make testing easy. It needs to avoid manual coding of dependencies. It also needs to remain ignorant of the dependencies until it’s told what to do. It also assumes all objects used in object creation remain loosely coupled (one of the cardinal sins often used in opposition to DI) and abide to API contracts (code to the interface, not the implementation!). In fact it presumes a common deferred approach – objects expect their dependents to be handed to them, but they never actively seek those dependencies by themselves. A sort of don’t call me, I’ll call you approach on the part of dependents.
The primary member of any IOC strategy is the Injector. You might see DI frameworks referring to the Container more often, but we’ll get around to why its called a Container – in there somewhere is always an Injector. As the name suggests, Injectors exist to inject dependents into dependees. Much as you do manually in the previous DI strategies.
Anyone familiar with objects will realise its role quite easily – the Injector creates all service objects with all of their own dependencies injected (preferably without creating an infinite loop though
) and injects those service objects into the client object being created before returning the client object for use. We’ll explore the concept and approach in another post soon, assess the current state of play in PHP of Dependency Injection, and see where DI can be dragged into actual source code in a useful way.
Until next time…
Can’t see the forest for the trees? Quit micro-optimising and try again.
Mar 10th
There’s a humourous story about a naive developer who spent months trying to speed up a single PHP application. The punchline is that it was me
. I was young and foolish, and spent all that time working with legacy PHP3 source code seeking optimisations. My inexperience wasted months (it was an open source app – not on the job thank you!).
Alex Netkachov’s PHP micro-optimization tips post to his blog creates a list of “micro optimizations” which include variations showing the speed of operations between loosely related similar alternatives. For example, a function is faster than a class static method which is in turn faster than an object method call. This is all well and true, but such optimisations (unless you are fantastically popular on the order of Yahoo or Google) rarely provide a measureable benefit.
When I was writing Performance Optimisation For Zend Framework Applications for “Zend Framework: Surviving The Deep End”, I highlighted this by reference to the practice of only optimising when you are certain to achieve a measurable improvement (easily assessed using xdebug). Micro optimisations rarely make a dent in a real application since there are countless other avenues of optimisation far more worth the effort. Don’t be like me in the 90s – don’t lose sight of the real optimisations by getting lost in applying micro optimisations.
This is not to blame Alex Netkachov whose list is actually dead on target! But to emphasise his own statement that application optimisation can offer a far greater benefit. I actually agree with his sentiment quite a bit, and I think it’s fair to say that his micro-optimisations, to an extent (e.g. static methods are a curse when testing which offsets any speed benefit by far), are the kind of stuff experienced developers apply without thinking – an automated part of their programming style balanced against the needs of object oriented applications.
Is this a contradictory stance? I don’t think so. I started using echo with comma delimited strings because someone pointed out it was faster than printing a concatenated string! The most sensible micro-optimisations are ingrained habits – not something you need to apply after the fact when it is way too late, and honestly, offer little added benefit for the extra cost of deliberately adding them.
The Mockery: An Independent Mock Object and Stub Framework for PHP5
Mar 5th
Every testing framework supports Stubs and Mock Objects, well…most of them. No wait, only one really does! SimpleTest. Yes, PHPUnit has a whole chapter on the topic – but let’s just say it’s implementation is more than a little broken.
The side effect of SimpleTest hogging the only true working Mock Object implementation has been an overwhelming de-emphasis in using Mock Objects in PHP. In a world where Unit Testing has given way to Test-Driven Design (TDD), and TDD shows signs of slowly being replaced by, or at a minimum learning from, Behaviour Driven Development (BDD), this lack of Mock Objects just won’t do. PHP needs something concrete in the area.
To that end, and right on the back of my previous MutateMe release, I put my considerable and legendary talents (which exist somewhere between my overweening ego, and my dictionary of GTA IV phone numbers) to work to create Mockery. Unfortunately my conscience forces me to acknowledge the invaluable input from Travis Swicegood (who recently released one of my favourite books on git!) who was deeply involved in the discussions and prototype code around Mockery’s predecessor, PHPMock, and therefore deserves a lot of blam…er…credit
.
You can download the initial PEAR package release of 0.1.0alpha from http://dev.phpspec.org/Mockery-0.1.0alpha.tgz or pull from git using the clone URL on the Github.com page at http://github.com/padraic/mockery.
Update #1: Support queries and/or comments and suggestions are also welcome to the Mockery mailing list at http://groups.google.com/group/mockery.
What Is Mockery?
Mockery is an independent Mock Object and Stub framework. It’s not tailored specifically to any one testing framework, rather it’s an entirely separate framework with a discrete API. The idea is that you can use this framework within PHPUnit, or SimpleTest, or anything else really, without being forced to rely on the built-in support (if any) that test framework provides.
Mockery was designed specifically to implement a form of Domain Specific Language (DSL). It makes extensive use of a fluent interface mixed with methods to approximate plain English. A mock object expectation could look like:
[geshi lang=php]$mock->shouldReceive(‘create’)->atLeast()->once()->atMost()->twice()->withAnyArgs()->andReturn(new stdClass);[/geshi]
There’s a lot packed into this single statement, and the natural flow of the DSL (there are no nested methods – only a linear fluent interface) is a major component in allowing your unit tests to remain readable. The API grammer itself is actually tiny – it’s how you mix and match them that makes things interesting and useful.
Being an independent framework, support for Mockery is non-existent in testing frameworks, but that’s not even necessary! Mockery will throw an exception of type Mockery_ExpectationException whenever the Mock Object is used in an unexpected fashion. Most testing frameworks natively report uncaught exceptions as Errors and print the exception’s message to the screen – so the only step needed is to ensure all Mocks are validated at the end of a unit test. Naturally, that would be a nice step to automate within testing frameworks but that’s not essential (maybe someone will hear my cry in the wilderness and adopt us though
).
What are these Mock Objects and Stubs?
Both Mock Objects and Stubs are variants of a Test Double. A Test Double is basically a fake object used to replace another real object in the test. Consider a simple scenario where a Model has a dependency on a Data Mapper, which in turn has a dependency on a database. You have two broad options:
1. Use a real database which means you are really testing the Model, the Data Mapper, and the DBMS as part of an integration test. This creates problems – databases are slow, need to be managed and reset, and why should the Data Mapper or even the database schema even exist yet?
2. Replace the Data Mapper with a fake – a Stub or Mock Object which implements an identical interface, but returns canned predictable responses with a negligible performance hit.
Many people will identify with the first option – there are enough arguments over whether to use a real database when testing to realise it’s a common approach. Fewer will identify with the second, since it has normally (outside of SimpleTest) involved creating special subclasses or mini-stubs.
The purpose of Mockery is not to pass judgement on any practice however – that’s my personal domain
. Mockery supports both Mock Objects and Stubs as equal citizens.
The difference between Mocks and Stubs is easier to grasp. A Stub is a static object – it’s created to return canned responses to all method calls. There’s nothing more complicated to learn – it’s that simple.
A Mock Object is a more interactive agent – it’s dynamic since you can literally program it to expect specific methods, with a specific order or number of calls, and return canned data depending on the preceding conditions. Essentially – it allows you to clearly define what interactions you expect the Mock Object to experience during a test. And then validate the Mock to see if your expectations were correct (pass) or incorrect (fail!). Yep – Mock Objectscarry verifiable assertions about what should happen in a test to the Mock.
This side of Mock Objects, asserting its expected behaviour, let’s you design objects in isolation by Mocking their dependencies – even if those dependencies do not yet exist. This has led their charge into mainstream TDD and BDD as a form of API exploration. As you add Mocks, you are basically designing a class’s interface to its dependencies. The concept of Mock Objects as a design tool is now fairly common if a relatively new idea.
Stubbing With Mockery
Mockery support Stubs in a fairly simple fashion. I remember Travis and I had this argument so many times I lost count
, so I divorced the idea of a Stub from a Mock to give Stubs a separate and ultra-simple implementation.
As an aside, Mockery offer two primary starting methods:
1. Mockery::mock()
2. mockery()
Both are interchangeable. For simplicity, and because Travis sold me on the idea, I prefer the function method. The function method is also more anonymous so you’re not constantly creating Stubs using a mock() method (to the confusion of whoever reads your tests). To create a Stub, simply call mockery() and provide it with a class name you want to create, and an array of public methods and their return values. Obviously, the class name cannot exist – if the class does already exist you’ll actually receive a Mock Object (but luckily that too will be confined to a Stub so you won’t notice anything different so it still qualifies as a Stub!):
[geshi lang=php]$stub = mockery(‘Foo’, array(‘print’=>’I am Foo!’));[/geshi]
The new object acts just like a class defined as:
[geshi lang=php]class Foo {
public function print() {
return ‘I am Foo!’;
}
}[/geshi]
Either way, the new object will have one thing for certain – it will be of type Foo, sufficient to pass any class hinting you use in your source code. You can set the configuration method array to return any scalar value or object you want, including other Stubs or even Mock Objects if you’re really feeling fiendishly clever.
With the Stub created, you can proceed to pass it into other objects expecting the interface and return values you configured for that test.
Mock Objects with Mockery
Since Mock Objects are more interactive, they offer a broader API. Like Stubs, they always inherit the class type of the class being mocked, and you can also set return values. Unlike Stubs, you can also set expectations!
So one day, this guy who looks like a Klingon, walks into a web development shop. Sounds like a bad joke, eh?
. He wants us to design a Ship Control System but gets nervous when asked about Weapons, Propulsion and Power. Left without a clue about these additional system, he hands over some interface requirements to stick to, and we start with one preliminary test (applying TDD).
[geshi lang=php]class BirdOfPreyTest extends PHPUnit_Framework_TestCase {
public function testWarpFactor8() {
$power = mockery(‘KlingonPower’);
$ship = new KlingonBOP($power);
// set Mock Object expectations
$power->shouldReceive(‘checkForWarp’)->once()->with(8)->andReturn(true);
$power->shouldReceive(‘deduct’)->with(80)->once();
// perform action required
$success = $ship->gotoWarp(8);
// add any necessary assertions?
$this->assertTrue($success);
// verify mock expectations
mockery_verify();
}
}[/geshi]
Since the class KlingonPower doesn’t really exist, we use a Mock Object to figure out how interactions should occur. From those interactions, as the example suggests, it’s a simple matter to actually go an implement the real thing! But since this test focuses on the Bird Of Prey control system, no need to run off yet. We don’t have full specs for a Power system, so we continue using Mocks to explore what its API could be.
Let’s implement the KlingonBOP class to make this test pass:
[geshi lang=php]class KlingonBOP {
protected $power = null;
public function __construct(KlingonPower $power) {
$this->power = $power;
}
public function gotoWarp($factor) {
if ($this->power->checkForWarp($factor)) {
$this->power->deduct($factor * 10);
return true;
}
return false;
}
}[/geshi]
As you can see, using the Mock Object guided us more clearly towards the API of a possible Power system class without requiring we actually implement it. A Stub would also have fit, but would not have provided the API behaviour and expectations we used when implementing the KlingonBOP class.
As for feedback on failures, here some example output from PHPUnit as an example. Reporting details should be improved in future iterations.
PHPUnit 3.3.14 by Sebastian Bergmann. .E Time: 0 seconds There was 1 error: 1) testAddWithFailingMock(AdditionTest) Mockery_ExpectationException: method get() called incorrect number of times; expected call 2 times but received 1
This is a really simple example, but hopefully it offers a small taste for the usefulness of both Mock Objects and Stubs.
The Mockery API
Here’s the run down of the current starting points to create a Stub or Mock Object:
mockery('Foo');
Create a new Mock Object with the class name and class type of ‘Foo’.
mockery('Foo', array('set'=>null, 'get'=>foo'));
Create a new Stub with the class name and type of ‘Foo’ defining two public methods and their return values.
mockery('Existing_Class');
Create a new Mock Object with a unique class name but a class type of ‘Existing_Class’. The unique class name is unimportant, but used to generate a Mock which is a subclass of any existing Class, Abstract Class or Interface.
mockery('Existing_Class', 'Custom_Name');
Create a new Mock Object with a class name of ‘Custom_Name’ but a class type of ‘Existing_Class’.
mockery('Existing_Class', array('set'=>null, 'get'=>foo'));
Create a new Stub with a unique class name but class type of ‘Existing_Class’ which effectively acts as a Stub (internally this is a variation on a Mock Object but that detail isn’t that important).
Additional tweaks and mixes of options will follow in the next release shortly.
mockery_verify()
Verify all currently unverified Mock Objects – this also exists as a separate method on every Mock Object for more granularity if needed.
The Mockery Mock Object Expectations API
Every Mock Object expectation starts with the shouldReceive() method. This is also the only non-namespaced method added to all objects, and is therefore a reserved method name. Other methods added dynamically to Mock Objects (or Stubs) are prefixed with “mockery_” to minimise the contamination of the object space with methods you might collide with one day.
A shouldReceive() call returns an instance of Mockery_Expectations which accepts expectations for the given method via a fluent interface, i.e. sequential method calls. These methods include:
never()
Expect the method to never be called. Same as times(0).
zeroOrMoreTimes()
Expect the method to be called zero or more times.
once()
Expect the method to be called exactly once. Same as times(1).
twice()
Expect the method to be called exactly twice. Same as times(2).
times(x)
Expect the method to be called x times.
atLeast()
Set a minimum of times to expect the method to be called by appending one of once(), twice(), or times().
atMost()
Set a maximum of times to expect the method to be called by appending one of once(), twice(), or times().
with(x[, y...])
Expect the list of arguments to be passed to the method.
withAnyArgs()
Expect any arguments including no arguments to be passed to the method.
withNoArgs()
Expect no arguments to be passed to the method.
withArgsMatching(x[, y...])
Expect arguments which, when cast to String, match the given list of Regular Expressions.
andReturn(x[, y...])
Set a return value to be returned from the method call. Multiple parameters set an ordered sequence of returns. In both cases, the last listed value is returned indefinitely to all subsequent calls once any preceeding listed values are used.
andThrow(exception[, message])
Set an Exception class to throw including an optional message.
ordered()
Set an expectation method to be called in a specific order. Each use of ordered() on a Mock Object determines the order, but any method expectations omitting this call remain free to be called at any time.
Conclusion
This is an initial alpha release, so while its hopefully sufficiently feature complete to be useful, its main objective is to illicit feedback! If you want new features, API changes, fixes, or have any ideas or comments whatsoever – please post a comment. You can also fork the git repository on Github.com if you want to make fixes so I can pull them back into my own repo for later distribution in a stable release.
