The Best Job In The World

I have had a lot of jobs. I started working full-time during the summer when I was 14 in the very odd family business of transistor fabrication. I also spent a few summers in the highly esteemed position of hospital kitchen lackey. When I was 19, I had the good judgement to prioritize partying above scholastic endeavors, and consequently dropped out of college. I have been working full-time ever since. Except for a year during my hippie phase when I stuck it to The Man by being an unwashed leaching bum. Take that, The Man!

I have had jobs that felt like indentured servitude. Jobs the weigh you down and crush your spirit, all the while screwing you with low pay and crappy benefits. Conversely, I have had jobs that shower you with gold bullion for doing hardly more than showing up for work. Ok, maybe not gold bullion, but you get the idea. I even spent a few years running my own software development company. And by “running” I mean running it into the ground so deeply in debt that it would never resurface. My shortest employment was with a telemarketing company for a total of 4 hours. I decided not to return after lunch on the first day because my reading of the sales shtick made an elderly woman on the phone cry.

I consider myself lucky to have worked in software development for the last 15 years. Liking what you do is a huge bonus, but I think it’s possible to be completely content with your job even if it’s not your hobby. 20 years ago when I ran the holy hell out of a box-making-machine to scrape a few extra bucks of performance bonus, I really did not give a crap about boxes per se, but I enjoyed the challenge of being the best box-making-machine operator I could be. I also enjoyed the challenge of leaving with the same amount of limbs I arrived with due to the overwhelming level of OSHA violations. The satisfaction of a job done right can be its own reward. But a few safety guards are nice too.

We all have different priorities for what is important in a job. Pay, hours, benefits, flexibility, not having to evade a noxious cloud created by a combination of the cleaning fluid in your mop bucket with a vapor leak from an atmospherically controlled wafer oven at a transistor factory. Surely I’m not the only one that has happened to? For me there is a simple metric that goes a long way to pushing a job from the “why must I endure this monotony of pointless existence” category to the “it’s not that bad” bucket. Bathroom cleanliness. Just kidding, it’s the people you work with (but who doesn’t like a clean bathroom?).

For me, the best job in the world is the one with the best people. I have a low tolerance for assholery. I don’t do drama. Unchecked egos make me wretch. Even disaffection gets my panties in a bunch. Maybe this is one of the reasons I like working from home – the additional layer insulating me from a potential personality conflict. Maybe it’s just my aversion to pants. And haircuts. And showering. I’m not suggesting work should be some sickly sweet love-fest, but working along-side motivated and friendly co-workers makes whatever you are doing inherently more enjoyable. Unless of course your arm gets ripped off by a box-making-machine.

Fun With PHPUnit

What is the first word that pops into your head when you think about unit-testing? I’m guessing “Fun”, amiright? Ok maybe not fun. Unless repeatedly slamming your head against a brick wall is your idea of fun. Trying to build comprehensive tests for existing code is an exercise in patience. Like the Olympics of patience. Sometimes when I come up for air and wipe the blood from my head (and wall), I realize that while I was toiling away in the unit-test dungeon, I stumbled on something useful. Maybe it’s a feature I had not explored before, or a solution to a tricky situation. Maybe it’s something that will help inject a little fun into your PHPUnit experience.

Before I start throwing out random ideas, let me say that I really like PHPUnit: lots of knobs, good documentation, active development. PHP is the Yoga instructor of programming languages, but that flexibility means it’s easy to write poor quality code. When code and unit-tests don’t get along, the right answer is to send the code to bed without dinner, and if it’s really bad, ground it for the rest of the week. We can blame the code all we want, but sometimes there is no choice but to tweak the system to find a way to make it all work.

One of the biggest obstacles in testing is state. Things like global variables, static values or class instances can easily create a situation in which a test passes when run alone, but fails when run as a part of a suite. There are other types of states to consider aside from just the disastrous PHP global namespace. Sessions for example. Or the state of data in a test db or on disk. Tests that fail intermittently are hard to debug, and usually it’s due to an overlooked state issue.

Tests should be as insulated and independent as possible, and PHPUnit has a feature called “runInSeperateProcess” that forces each test to run in its own PHP process. Using this feature is not as simple as it sounds. If you have a bootstrap file defined in your phpunit.xml file, and it includes any code that defines a constant, you will get an error about redefining said constant in your tests. What gives? I thought each test runs in its own process? It does, but from what I can determine (using the throw-it-against-the-wall method), only the test code itself is run per-process. Assuming that poorly substantiated statement to be true, here is a pattern that does work with process separation.

Process Separation

First the phpunit.xml file, WITHOUT a bootstrap

<phpunit strict="true" colors="true">
    <testsuite name="my_awesome_tests">
<file>./my_awesome_tests.php</file>

Then the my_awesome_tests.php file, with the bootstrap included in the setUp() method and the @runInSeperateProcess and @preserveGlobalState annotations.

<?php

class My_Awesome_Tests extends PHPUnit_Framework_TestCase {

    public function setUp() {
        require 'bootstrap.php';
    }

    /**
     * @preserveGlobalState disabled
     * @runInSeparateProcess
     */
    public function my_test_one() {
    }
    /**
     * @preserveGlobalState disabled
     * @runInSeparateProcess
     */
    public function my_test_two() {
    }
}
?>

Finally, the bootstrap looks something like this

<?php

/* all the things */
error_reporting(E_ALL | E_STRICT);

/* determine current absolute path used for require statements */
define('APP_PATH', dirname(dirname(__FILE__)).'/');

/* get mock objects */
require APP_PATH.'tests/mocks.php';

/* get the code we want to test */
require APP_PATH.'lib/framework.php';

/* get the stubs */
require APP_PATH.'tests/stubs.php';

?>

mocks.php contains stand-in objects used as arguments to methods we want to test. The stubs.php file contains wrappers around abstract classes and traits so we can test them more easily. One advantage of this pattern is it makes it possible to pre-define constants in the setUp() method before the code being tested is loaded, so a test can exercise a code path that triggers on a non-default constant value (Assuming the code being tested checks for an already defined constant). Since mocks are loaded before the code being tested, we can also leverage this to override things unfriendly to testing.

Overriding Stuff

It’s good practice to limit mocking and overriding to a minimum. The more code that is mocked out, the less actual code that is being tested. There are however some built-in PHP functions that simply don’t play nice, like setcookie or header or session_start or error_log or die – you get the idea. Using the pattern as described above in “Process Separation”, we can easily add some override behavior to deal with these problems (sadly this does require changes to the code being tested).

In our mocks.php file we create a class of all static methods for built-in functions that don’t play well with others.

class BuiltIns {
    public static function php_header($header_str) { return true; }
    public static function php_die($msg) { return true; }
    public static function php_error_log($str) { return true; }
}

In the code to be tested, we setup a mirror image of this class that runs the actual built in functions, but only loads if the class is not yet defined.

if (!class_exists('BuiltIns')) {
    class BuiltIns {
        public static function php_header($header_str) {
            return header($header_str);
        }
        public static function php_die($msg=false) {
            return die($msg);
        }
        public static function php_error_log($str) {
            return error_log($str);
        }
    }
}

Then we replace occurrences of these built-in functions in the code to be tested. So this:

if ($error_str) {
   error_log($error_str);
}

Becomes this:

if ($error_str) {
   Builtins::php_error_log($error_str);
}

WOOT! Now we don’t have to worry about an errand error_log spoiling our unit-test party. We can even do something useful in the mocked out versions, maybe a fake session_start() call can populate $_SESSION or another constant in setUp can toggle success or failure from the mocked out function. The sky is the limit people!

Coverage

I have only recently started to look at PHPUnit’s coverage options. When I first tried it out, it bailed with a cryptic message and I was sad. Some head scratching and a few apt-get installs later, I was blown away. The HTML coverage report is incredibly useful. By default it sucks up other included files, so if you are dealing with a big code-base it can be handy to limit coverage to just code you are actively testing. I like to define these limits and enable the coverage report in my phpunit.xml file with something like this:

    <filter>
        <whitelist addUncoveredFilesFromWhitelist="false" processUncoveredFilesFromWhitelist="false">
            <directory suffix=".php">../lib</directory>
            <exclude>
            <file>../lib/not_tested.php</file>
            </exclude>
        </whitelist>
    </filter>
    <logging>
        <log type="coverage-html" target="./coverage.html" charset="UTF-8" highlight="false" lowUpperBound="35" highLowerBound="70"/>
    </logging>

The report is comprehensive. It has summary charts for coverage, complexity, risk analysis, and even line by line detail that makes it brain-dead easy to see what your tests are hitting, and more importantly, what they are missing. Coverage alone does not make a good unit test, but it’s a great tool to help improve your tests.

Extending PHPUnit_Framework_TestCase

This post is really dragging on so I will leave you with one additional trick I came across building unit-tests for a billing system. We wanted a test suite that we could run across a variety of products, but the tests code would be nearly identical. Duplicating the tests for each product was a maintenance nightmare. We needed a way to run virtually the same test code across multiple products. Here is what I came up with:

Start by extending the PHPUnit_Framework_TestCase class with an abstract class. This will be where the actual test code lives.

<?php

abstract class Base_Tests extends PHPUnit_Framework_TestCase {
    public function test_something() {
    /* your normal test code goes here */
    }
}
?>

Next extend that class for each product you want to test, and define the product as a member variable in the setUp() method so it can be accessed from the test method scope:

<?php
class Product_A_Tests extends Base_Tests {
    public function setUp() {
        $this->product = 'product a';
    }
}
?>

PHPUnit will not try to run the tests in the abstract class, but it will find and run the tests in the classes that extend it. For each product you want to test, just extend the base class and define the product details in setUp().

I’m hardly a PHPUnit expert, and there are surely improvements to these ideas or even completely better ways to accomplish the same thing. All of these examples minus the last one were taken from a unit-test suite for some Open Source software I’m working on. You can see the still-in-progress test code at Github, and an example of the coverage report from PHPUnit at jasonmunro.net.

You Got Your Javascript In My Peanut Butter

I have always tried to embrace a minimalist approach to software design. Even early on in my career when I had no idea what I was doing. In those days I rode a horse-drawn carriage to work and used a pointed stick to scratch PHP3 code directly onto the server’s hard-drive platter. Good times. Back then JavaScript was like window dressing – a bit of flair for the UI – definitely not something you relied on for the web application to function.

It was possible some of your users might not have JavaScript support, and at the time we actually cared about those users. The first two major Open Source web applications I built both worked without JavaScript. I’m pretty sure that increased our user-base over the period of a decade by at least 1. Totally worth it.

These days it seems nobody cares about users without JavaScript. Even me. I care only enough to display a noscript tag with a message stating it’s required, but only when I’m feeling particularly ambitious. In my head I picture users with JavaScript disabled as middle-aged versions of Kip from Napoleon Dynamite, all of whom used punch cards in college, started in IT as a data processor in the late 80’s, and are still running Windows NT (or wish they were). Now that I think of it, if they are running NT they probably should have JavaScript disabled.

As much as I dislike the language – and I do – it makes sense to offload parts of an application to the client. Let’s face it, you can’t be all super-web 3.0.1 if you don’t make constant AJAX requests in the background the moment a page loads. I may be a neck-bearded curmudgeon, but I have begrudgingly come to accept that JavaScript is the best way available at this point in time to improve web applications past what HTML5 brings to the table. To a point.

As an industry we seem to be lurching towards JavaScripting all the things. JavaScript only interfaces! JavaScript on the server! JavaScript interpreters written in JavaScript! The older I get the more I try to balance my skepticism of new ideas with a willingness to keep an open mind, but I am having a hard time catching a ride on the all-JavaScript-all-the-time bandwagon. Maybe I am biased by the five years I was forced to use a bloated unintuitive framework for a former employer, of which the only thing I remember (aside from being gigantic) was how effin horrible it was to work with. But probably not. Additionally, I seem to have missed the memo to web developers that everyone in the world now has high speed internet so we can push gobs of scripts client-side even to perform the most simplistic task. I’m slightly offended nobody told me. Have I also been walking around with a booger hanging out of my nose? Come on people, throw me a bone here.

Running JavaScript on the server is interesting, but for me it’s interesting in the same way that a squirrel water-skiing behind a toy boat in a backyard pool is interesting. I realize event-driven non-blocking I/O is the new Holy Grail of server-side processing, and buzzword-laden start-ups are required to use it in their stack in order to get funding, but I just can’t seem to let go of a well tuned web-server with a fast scripting language and moderate use of JavaScript in the client as an effective foundation for building web applications. Then again I don’t have good reading comprehension because my eyes are worn out from years of articles about the latest technology fad revolutionizing web development, so maybe I am just missing the toy boat.

I didn’t start this post with the intent of bashing JavaScript, and the fact that I now rank it slightly above “necessary evil” (but still below “creepy cousin”) is as close to an endorsement of the language as I have ever come. One could even conceivably describe it as being “handy” for limited purposes *grinds teeth*. Maybe someday I will be telling my great grand-kids about the crazy old days when there were other programming languages, way back before every conceivable app was ported to JavaScript and all knowledge of anything else was lost to generations past. Somehow I doubt it.