Drupal uses extended version of SimpleTest for automated testing. It provides two parent classes for test cases: DrupalWebTestCase and DrupalUnitTestCase. Documentation describes the DrupalWebTestCase as the one appropriate for “typical Drupal tests”. However, a quick look at its setUp method is enough to notice that when this class is used a lot is done at each test run, including a lot of pretty slow database work.

I am a recovering Java developer. As such, I was trained hard and long to write tests not as an afterthought but as a design guide for the actual working code, before the working code (some call it Test-Driven Development). That, however, inevitably assumes running your tests very frequently, against breaking code. Photo copyright by Kay
Kim(김기웅)
http://www.flickr.com/photos/8906966@N02/3986997574/sizes/m/in/photostream/ If you write your test code as a sub-class of DrupalWebTestCase, however, that is not really an option. With WebTestCase, each test run takes several seconds (even on a very capable multi-core linux servers) and those seconds really, really add up! I am easily irritable when I write code. If something consistently wastes my time, I stop using it.

DrupalUnitTestCase on the other hand is much lighter and executes pretty fast. At the first glance it’s a much better alternative to DrupalWebTestCase. Unfortunately, it is not without some significant shortcomings. As mentioned above, I am used to writing tests before the working code. Which means: when I run tests, code is broken and I need to debug it. For me, debugging a server-side application means using some sort of logging (assume, if you wish, that I am philosophically opposed to code tracing using inspection tools). Problem: there’s no way to log anything from a child of DrupalUnitTestCase. Ouch.

Drupal’s native “watchdog” function does not work (not even with logging to syslog, which additionally throws errors if devel module is enabled) because Drupal is not fully bootstrapped for unit tests and, for reasons unclear to me, PHP’s error_log() does not produce any output from test classes, either.

The solution I could find is fixing error_log in your test case class’s setUp() method with something like:

  public function setUp() {
    parent::setUp('modulename');

    //-- Can't use 'file_public_path' because simpletest overrides it.
    $logfile = conf_path() . '/files/test.log';
    ini_set('log_errors', 1);
    ini_set('error_log', $logfile);
  }

which will allow you to log messages with error_log() to “sites/default/files/test.log” and may make using unit tests in Drupal relatively possible.

The remaining problem with Drupal and unit testing is that Drupal insists on using database for storing information about modules (and consequently available hooks etc.). Since Drupal is not fully bootstrapped in unit tests, a lot of this information is missing and you have to be very careful with what functions you can call.

Oh well, life ain’t perfect.