Writing unit tests for your code is widely regarded as a best practice. There are many excuses for not writing tests: time, cost, and the fun factor. Excuses aside, there are some Good Reasons to write tests for your code. I just discovered one today.
Write tests, you might learn something…faster
I’m working on an API integration that requires a bit of AES-256 encryption. Getting that worked out in PHP took some surprising turns, so just to be sure that I was getting all the details right (such as initialization vector size) I decided to write a unit test for my mcrypt wrapper library.
Since this library had worked well in other projects, imagine my surprise when the first AES-256 encrypt-decrypt test failed:
$ phpunit *
PHPUnit 3.7.8 by Sebastian Bergmann.
Time: 0 seconds, Memory: 2.50Mb
There was 1 failure:
1) EncryptionAes256Test::testEncryptDecrypt with data set #0 ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz')
Failed asserting that two strings are equal.
+Binary String: 0x4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656668696a6b6c6d6e6f707172737475767778797a00000000000000000000000000
Tests: 4, Assertions: 7, Failures: 1.
Echoing out the decrypted string proved just as bizarre:
It seems that mcrypt pads the string with enough null characters (
\0) to match the block size, and unlike strings in C, PHP strings do not necessarily end with the first null character.
The fix was obvious:
$decrypted = rtrim($decrypted, "\0");
Guess what? By investing time in a simple unit test, I unexpectedly learned something new about PHP, AND saved myself quite a bit of time debugging an API call that would not have worked.
I’d say it was worth it.
Get my day one takeaways here.
Day two at PHPCon in Nashville, TN was packed with lots of information that frankly, I’m still digesting. It was well worth the trip and ended much too quickly!
Download my notes (PDF)
In his “brain dump,” Rasmus Lerdorf shared a collection of unrelated but very useful tips and observations about PHP.
- PHP is the bottleneck, there is no significant difference between nginx/lighthttpd/apache
- Error handling is not optimized in PHP because it should be an infrequent event. Set
error_reporting = -1
realpath_cache_size in PHP 5.2 can cause excessive filesystem STATs
- Use gearman for out-of-band processing. Threads aren’t needed in PHP.
- Don’t overload apache (8 core CPU = 25-30 apache clients; never more than 50)
- Deploy processes should be atomic and robust (can use Capistrano or Rasmus’ own weploy script)
- Node.js-style event programming is fast and easy (see http://php.net/libevent)
Slides: http://talks.php.net/show/phpcon2011 (ya gotta love the homegrown web-based presentation system!)
The Original Hypertext Preprocessor
Drew McLellan‘s presentation was particularly relevant for me in my role as CTO at Company52, and I consider it one of the best presentations at PHPCon. Drew’s goal was not to market Perch (although he did an awesome job of it without even trying), but rather to share his philosophy of what really great client support is all about, and how it has impacted his work.
- Throwing new features at a problem often doesn’t solve it. Functionality is not enough.
- Find ways to reduce support requests.
- Every support request should be unique (no FAQs).
- Fix areas of confusion rapidly.
- Support your own software – programmers should see issues firsthand.
- It’s OK to be opinionated (“WYSIWYG is evil”), but don’t be dictatorial. It’s not our place to tell people how to work.
- Help customers look good in front of their clients.
- Accept when users are having problems.
- Really great developers solve problems. Excuses simply are not helpful.
The WonderProxy story
Paul Reinheimer shared the story of how he built (and self-funded) WonderProxy, born out of a personal need to test applications that use IP-based geolocation.
- Mistakes – “crouch and hope you don’t get hit”
- No account de-activation
- NIH – wrote paypal IPN code instead of re-using own code
- Mixing Linux distros
- Server account renewals
- Afraid to look at profitability numbers
- Old strategy: blog about problems we encounter – competitors find posts
- New strategy: blog about problems customers have – bring customers instead of competitors
Is it Handmade Code If You Use Power Tools?
Laura Beth Denker of Etsy shared an overview of their continuous integration processes, and how it has greatly improved both confidence and deployment speed. True to Etsy style, Laura came dressed in a handmade outfit from a Nashville-based Etsy vendor, earning a “too much swag” tweet from one listener!
- NEED CONFIDENCE in your code
- Effective testing strategies include functional (human) testing, integration testing (database), and unit testing (foundation)
- Don’t use random data in unit tests
- Test each case in control structures
- Use DBUnit for testing database interaction
- Tests should run rapidly
- Group unit tests and target test groups to run
- network tests (third-party APIs)
- smoke, curl, regex
What happened to Unicode in PHP
Andrei Zmievski’s talk was a frank de-briefing of the failed attempt to bring native Unicode support to PHP6. Although this story is a rather personal one for Andrei, he was honest and incorporated a few surprisingly hilarious bits of humor. The conclusion: native Unicode support will only come to PHP if and when the community wants it — and is willing to put noses to the grindstone. The task is simply too big for his elite band of 10 (including Rasmus himself). Most of the content was historical in nature, but there were a few nice tidbits of information.
- Complete I18N is more than language stuff:
- Character set
- Date/time formats
- Currency formats
- Collation (sorting, contractions – thanks to Andrei for finally helping me to understand what a “collation” is)
pecl/intl has some useful classes left over from the PHP6 unicode project (
Terry Chay’s closing keynote wove a common thread through all of the presentations given at PHPCon, along with a heaping helping of humor (seedy at times). My favorite part were the Chayisms: http://phpdoc.info/chayism/