You all should be testing your plugins. You know that, right? Regardless of whether or not you know that, chances are you have NO EARTHLY IDEA how to accomplish it. I've spent a while getting tests up and running for the release of my plugin sfThemeGeneratorPlugin. The truth is, the native testing framework is filled with hacks. This post illustrates how to compound upon these hacks so they do your bidding. We will use the Lime testing framework bundled with symfony.


The Why: First of all, why test your plugins? Plugin tests ensure you won't break your buddy's project when you push minor fixes. Also, it gives your buddy this same confidence when upgrading to a new release. Plugins are self contained libraries. They should be able to be tested independently of a particular symfony project. In fact, they should be able to run with any symfony library you provide to them, granted the release is supported by your plugin. A plugin's test should be independent of every dependency it has. Symfony is a dependent library, as are any plugins required for your plugin to run. With the ability to define the paths to your plugin's dependencies, you can quickly test your plugin across multiple releases of those dependencies. It also allows your plugin's users to run your tests within the context of their application. Who has two thumbs and an awesome plugin? You do my friend. You do. The How: Our plugin should contain an executable file to run its tests. The executable should accept parameters for the paths to any of its dependencies. The plugin in my example accepts the symfony_dir argument like this:
$ cd sfMyAwesomePlugin/test/bin/
$ php prove.php
Symfony directory not found.  Please set $_SERVER['SYMFONY'] or provide a --symfony_dir argument
$ php prove.php --symfony_dir=/usr/local/lib/symfony/RELEASE_1_4_0/lib
All tests successful. Files=2, Tests=12
At the same time, we want to be able to run our tests as a part of our application test suite. Luckily, this part is feasible through the existing Symfony test framework.
# Task to run all tests in your plugin
$ php symfony test:plugin sfMyAwesomePlugin

The Process

So how do we do it? First, we need to include a symfony project fixture in the plugin. This is required for both unit and functional tests. We'll add this in test/fixtures/project. Now before you post a picture of Xsibit, let me explain why this isn't a terrible idea. Even though the symfony framework is rather robust, you can pear it down quite a bit. Take it down to bare bones and you are left with only 6 of files and 10 directories. This is the minimum directory structure needed to run a symfony project fixture:
# symfony project fixture
The files and folders with asterisks(*) next to them are only needed if you're using a the database layer. For this, I strongly suggest using sqlite. We will copy the fresh database over each time the tests run. Build your test database by running the DB build task in the fixture project (For doctrine and symfony 1.3+ you would use doctrine:build --all). You can download the symfony project fixture here. Now that we have a project fixture, we need to add our execution binary. We'll use a prove.php file. This is a simple PHP execution file, and does nothing but include your bootstrap file and run your tests. This is also where we want to check to make sure the path to your symfony library is specified. Add this file to /path/to/plugin/test/bin/prove.php Next we want to have a Bootstrap class. I took the liberty to make the sfPluginTestBootstrap class. I refuse to write a single line of PHP procedural code that is not strictly necessary. This file will determine the symfony directory, autoload symfony core, and register the setup and teardown functions. This class also begs you to extend it for your project if needed. Add this file to /path/to/plugin/test/bootstrap/sfPluginTestBootstrap.class.php Finally, we need to have a bootstrap file. This is similar to the bootstrap you'll find in any of your project's tests. While I am no more a fan of this than you, this is the way things work with Lime. Mine looks like this: bootstrap.php. This will be the sole include at the top of each test. This will allow you to run each test manually via command line ($php sfMyAwesomePluginTest.php) and via the prove.php file. Wootness. Add this file to /path/to/plugin/test/bootstrap/bootstrap.php

The Result

When you get to this point, you should have something like this in your plugin's test directory: Sample Plugin Test Directory So what do we need now? The good news is... that's pretty much it! Now we just need to add the test files themselves. These will look exactly like a regular symfony test. That's right, you can write a unit or functional test in whatever project you're using, and just move the files into your plugin. You may need to adjust the bootstrap include at the top of each test, but this approach follows the symfony convention, so even that is unlikely. That's nice, right? Now sit back and enjoy all the benefits that come with having beautiful test coverage. Confidently notate compatible symfony versions. Give your users the piece of mind knowing your plugin is compatible with their application. And refactor with confidence! I basically had to cage fight a rabid bear to figure all this out. Now all you need to do is follow these steps. Give my wounds purpose, and test your plugins.