PHP, Zend Framework and Other Crazy Stuff
Archive for November, 2007
Mutation Testing Brain Dump
Nov 27th
A few thoughts I’m pulling together regarding Mutation Testing for PHPSpec (that’s the Behaviour-Driven Development framework I’m working on).
Mutation Testing is like testing, for tests. The idea is actually quite simple. Mutation testing adds small changes to your source code on the assumption that changing something, will most likely break it, which in turn means at least one test/spec should fail. If no tests fail, then it means our tests were incapable of detecting the deliberately introduced problem (i.e. we need to add more tests/specs to detect similar mutations). The reason why it’s useful it that it gets around the problem of being over reliant on code coverage - just because some code executes when running tests, doesn’t prove the tests will detect problems with it!
In PHP I’ve only ever seen one real implementation of Mutation Testing, which seems to be coming along for PHPUnit. Should be a lot of fun when that’s finished and someone applies it to their PHPUnit test suites . PHPUnit mutations rely on a few PECL extensions like runkit and Parse_Tree but I really wanted to try something even dumber so the runkit/parse_tree dependencies are not required. My way is not going to be relying on changing class definitions mid-process.
The main culprit in all of this will the PHP Tokenizer. If you’re not familiar with it, the Tokenizer functions let you access the Tokenizer in the Zend Engine so you can analyse PHP source code without fiddling about with byte-by-byte or PCRE based parsers you’d have to write otherwise. For example:
[geshi lang=php]$source = ‘
$tokens = token_get_all($source);
var_dump($tokens);[/geshi]
This sample will output tokens as:
array(10) { [0]=> array(3) { [0]=> int(367) [1]=> string(6) ” int(1) } [1]=> array(3) { [0]=> int(309) [1]=> string(3) “$op” [2]=> int(1) } [2]=> string(1) “=” [3]=> array(3) { [0]=> int(305) [1]=> string(1) “1″ [2]=> int(1) } [4]=> string(1) “;” [5]=> array(3) { [0]=> int(370) [1]=> string(1) ” ” [2]=> int(1) } [6]=> array(3) { [0]=> int(316) [1]=> string(4) “echo” [2]=> int(1) } [7]=> array(3) { [0]=> int(370) [1]=> string(1) ” ” [2]=> int(1) } [8]=> array(3) { [0]=> int(309) [1]=> string(3) “$op” [2]=> int(1) } [9]=> string(1) “;” }
This looks like double dutch, but it's actually quite simple. Each of the 10 array elements is either a string or a sub-array. Each sub-array represents a token, and has three elements - the token number, the content, and the line number it was found on. The token number is equivelant to a token constant like T_WHITESPACE (the value 370) - hands up if you recognise the T_* format from all your error messages .
Back to the topic, you can use this token analysis to locate places to apply mutations. Maybe I want to replace the $op=1 piece of code with $op=2 (a test relying on value being 1 would surely fail then!). This is easy using tokens - just search for all tokens of type T_LNUMBER (an integer) and replace them with some random value. I could replace variable names by searching for T_VARIABLE tokens, and so on.
Once a mutation (just one before rerun tests or specs to see of the mutation correctly generates a failure) is applied, you can reconstruct the source code string using a simple function like, and use the mutated code to replace the original clean stuff.
[geshi lang=php]function getSource(array $tokens) {
$str = '';
foreach ($tokens as $token) {
if (is_string($token)) {
$str .= $token;
} else {
$str .= $token[1];
}
}
return $str;
}[/geshi]
The way I'm thinking of playing with this mutation processing style is to do away with any external dependencies (no PECL to worry about phpizing) and just employ a working copy of the source code tree you want to apply mutation testing to - yep, just copy the code and tests somewhere where it's safe to generate mutations and run tests without effecting the original source. Pretty simple - I'll even let you define where to copy to .
Then it's a simple matter of creating a list of mutations to apply, apply them one by one (restore the original files after each mutation run) and call the local command line test/spec runner after each incremental mutation. As you can guess, mutation testing takes longer to run than normal testing (new test run per mutation in a new PHP process), but it will cease the second 1 failure/error/exception is detected. Also it would still be far far faster than compiled languages (which can be horribly slow).
The other benefit of this is that the mutation system would be independent of the testing or BDD framework. You could conceivably use it for PHPT or SimpleTest, as well as PHPSpec (conceivably when framework adapters are implemented, that is ). Even PHPUnit, though their built in mutation testing once finished will likely integrate better and run faster (won't require new PHP processes).
When I get around to playing with this in depth I'll post a little more with some actual code. Maybe to the usual suspects on the Devnetwork Forums to critique.
Ruby Testing Tools Missing From PHP
Nov 23rd
Warning: This entry uses the word “Ruby” in a context that explains how in “one aspect” it’s “better than PHP”. Try not to cry…;). If you can’t live with Ruby having a few tools PHP doesn’t quite have yet, you shouldn’t read any further.
To throw out a few keywords so some cross-language developers can sagely nod their heads: Autotest, Mutation Testing, Mocha, Rspec, Heckle…what’s that other one? Hpricot.
Anyways, here’s the pitch. I’ve been using Ruby for a year now and my pet peeves with PHP started getting a bit too much to comfortably endure. Luckily, for all my PHP readers who think I’m brilliant (or at least good enough to fake it Shhh…), I don’t like developing web applications with Ruby, or that thing Rails. Whatever it is. It’s a framework, right? So I’m on a splurge of writing PHP tools for the same things in cahoots with folk like Travis Swicegood (edit: as far as I know Travis is totally innocent of being a Ruby-Lover - I’m the one you want to flame for being “rubyesque” or whatever
).
But Ruby has a few non language-specific testing ideas I love to bits. Behaviour-Driven Development is one of them (sorting that out with PHPSpec, and PHPT is showing some lighter weight advances which are worth noting). Another is ZenTest’s Autotest.
Autotest rocks. Yabba dabba doo style.
If there was ever something I’d use Sara Goleman’s introduction to the mystical art of PHP Extension writing for (great book), it’s to interface to every notification daemon/app I have running on my OS’s. You see, using any testing framework I open my IDE, edit some classes and their respective tests, flip to the command line, re-run my tests, wait a while, and get a result. It’s all nice - and it sinks time once the tests reach the level of needing anything beyond a split second to run.
How much nicer then to have a tool checking all my project files for modifications, running only the subset of tests effected, and reporting results via a popup notice with green/red feedback colours - all in a second or two? What? No “phpspec -r” or “pear run-tests -rq”? No running all tests, or selecting a specific group/directory? Absolutely not. I don’t even leave the IDE window… It’s autotest afterall - human interaction not required.
Then there’s Ruby’s Heckle for Mutation Testing. Actually PHPUnit has something on this already (there’s another Sara Goleman link to PECL’s runkit which it uses). Not in the release branch yet, but hopefully it’ll get in there at some point. For PHPSpec specifically I was thinking about planning mutation testing for a few months time, but couldn’t really think of a good solution. PHPUnit’s wiki has some posts from the Mutation Testing author (part of the Google Summer of Code) and some of the dependencies from PECL seem to carry some small problems making it more difficult than it should be.
I noted earlier today it may pay to remember PHP runs from the command line - so you can use multiple processes, and access multiple copies of class definitions. You could feasibly create 100 classes called Logger, mutate them on the fly on a per process basis, and throw them at tests all day long. You’d only need 100 sequential PHP processes (one per mutation - nothing odd there for a PHPT user) tied together to a Heckle-like PHP clone. The only concern would be using it only on code which is clever enough not to redeclare existing classes. Sounds like a simpler route compared to using PECL runkit et al. in the one process.
Just to finish up there’s Ruby’s Hpricot. Hpricot is plain annoying, though PHP isn’t too far behind it. For many things DomDocument just works great. Hpricot however just feels better - how can you resist using a lean API like:
[geshi lang=ruby]doc = Hpricot(“That’s my spoon, Tyler.”)
doc.at(“b”).swap(“fork“)
doc.to_html
# => “That’s my fork, Tyler.”[/geshi]
As an HTML parser and general toolkit it’s addictive. It even parses XML . You could probably just write a clone right on top of DomDocument and who’d care?