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. .F.. 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. --- Expected +++ Actual @@ @@ -'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz' +Binary String: 0x4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656668696a6b6c6d6e6f707172737475767778797a00000000000000000000000000 /Users/jhill/Sites/mrtz_010/Source/tests/EncryptionTest.php:53 FAILURES! Tests: 4, Assertions: 7, Failures: 1.
Echoing out the decrypted string proved just as bizarre:
string(51) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz" string(64) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz"
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.