PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1

CHAPTER 18 ■ TESTING WITH PHPUNIT


The most insidious bugs don’t cause the interpreter to report that something is wrong. They hide in
perfectly legal code, and they silently break the logic of your system. Many bugs don’t manifest where
you are working; they are caused there, but the effects pop up elsewhere, days or even weeks later. A test
framework can help you catch at least some of these, preventing rather than discovering problems in
your systems.
Write tests as you code, and run them often. If someone reports a bug, first add a test to your
framework to confirm it; then fix the bug so that the test is passed—bugs have a funny habit of recurring
in the same area. Writing tests to prove bugs and then to guard the fix against subsequent problems is
known as regression testing. Incidentally, if you keep a separate directory of regression tests, remember
to name your files descriptively. On one project, our team decided to name our regression tests after
Bugzilla bug numbers. We ended up with a directory containing 400 test files, each with a name like
test_973892.php. Finding an individual test became a tedious chore!


Writing Web Tests


You should engineer your web systems in such a way that they can be invoked easily from the
command line or an API call. In Chapter 12, you saw some tricks that might help you with this. In
particular, if you create a Request class to encapsulate an HTTP request, you can just as easily populate
an instance from the command line or method argument lists as from request parameters. The system
can then run in ignorance of its context.
If you find a system hard to run in different contexts, that may indicate a design issue. If, for
example, you have numerous filepaths hardcoded into components, it’s likely you are suffering from
tight coupling. You should consider moving elements that tie your components to their context into
encapsulating objects that can be acquired from a central repository. The registry pattern, also covered
in Chapter 12, will likely help you with this.
Once your system can be run directly from a method call, you’ll find that high level web tests are
relatively easy to write without any additional tools.
You may find, however, that even the most well thought-out project will need some refactoring to
get things ready for testing. In my experience, this almost always results in design improvements. I’m
going to demonstrate this by retrofitting one aspect the WOO example from Chapters 12 and 13 for unit
testing.


Refactoring a Web Application for Testing


We actually left the WOO example in a reasonable state from a tester’s point of view. Because the
system uses a single Front Controller, there’s a simple API interface. This is a simple class called
Runner.php.


require_once( "woo/controller/Controller.php");
\woo\controller\Controller::run();
That would be easy enough to add to a unit test, right? But what about command line arguments?
To some extent, this is already handled in the Request class:
// \woo\controller\Request
function init() {
if ( isset( $_SERVER['REQUEST_METHOD'] ) ) {
$this->properties = $_REQUEST;
return;
}


foreach( $_SERVER['argv'] as $arg ) {
if ( strpos( $arg, '=' ) ) {

Free download pdf