New symfony plugin – sfPropelTestPlugin simplifies unit tests

If you’ve ever tried to write a symfony unit test for a model class – or for any piece of code that interacts with the database – then you know what a headache it can be. sfPropelTestPlugin to the rescue! This plugin loads all the necessary symfony components for database interaction, and goes a step further: test data is automatically reloaded to the test database at the beginning of each test case, so you don’t have to worry about your tests interacting with each other. Here’s an example of a unit test written with sfPropelTestPlugin:

class myUnitTest extends sfPropelTest
{
  public function setup()
  {
    $this->bob = UserPeer::retrieveByPK('bob');
  }

  public function teardown()
  {
    $this->diag('Test method complete!');
  }

  public function test_user()
  {
    $this->is($this->bob->getId(), 'bob', 'Bob exists!');

    $user = new User();
    $user->setFirstName('Joe');
    $user->setLastName('Smith');
    $user->setUsername('joe');
    $user->save();

    $joe = UserPeer::getBy(UserPeer::USERNAME, 'joe');
    $this->isa_ok($joe, 'User', 'Joe exists!');
  }

  public function test_dataDelete()
  {
    $this->is($this->bob->getId(), 'bob', 'Bob still exists!');

    $joe = UserPeer::getBy(UserPeer::USERNAME, 'joe');
    $this->ok(!$joe, 'Joe no longer exists.');
  }
}

$test = new myUnitTest();
$test->execute();

If you’ve written tests in Ruby on Rails, the above should look familiar. If not, let’s go through the code:

The first two lines are setup: The first line tells symfony what application to test – in this case, “myApp” – and the second line includes the code we need to test against the database. Next we define our “test case” – a class that extends sfPropelTest, which is itself a child of lime_test. Every method that begins with “test_” will be called in turn, with our test data being reloaded between each call. Also, the setup() method, if defined, will be called immediately before each test method, and the teardown() method, if defined, will be called immediately after. The last two lines create a new instance of our test suite, and call its execute() method, which runs our tests.

There you have it – a quick and painless way to run unit tests in symfony. One less excuse for not writing them!

  1. NiKo’s avatar

    Great. Stuff.

    Furthermore, I guess this should be bundled with Propel itself.

  2. Markus’s avatar

    this should be bundled with the sfPropelPlugin, not propel itself

  3. elbouillon’s avatar

    So GREAT ! Thx

  4. ico’s avatar

    Hello Rob,

    Actually your plugin suppose to clear the data insert on every test, it inserts the data OK, but since they are never cleared, the properly constructed schema returned duplicated records and no more than the first test could be executed :)

  5. rafal’s avatar

    Hello Rob,

    I have similar problem to that mentioned in the previous post. Data should to be cleared before it is inserted on every test but it is not. Only first of test methods works because it is executed on empty database. What is more weird plugin worked before but has stopped recently and I have no idea why. I am interested if more people have similar problem and of course a solution :)

    Besides, great work :) Thx

  6. Gabriel Franco’s avatar

    Hello Ico,

    I had the same problem as you, the solution was to override the teardown method to clean the database after every test execution.

    Another problem I had also was with the propel-unit.php.

    I don’t know if this is a real problem, but I just managed to make the plugin work changing the line 34 from:

    ,SF_ROOT_DIR.’/apps/theApp/lib’ // Location myapp application

    to

    ,SF_ROOT_DIR.’/apps/’.SF_APP.’/lib’ // Location myapp application

    After that the plugin worked really fine.

    Nice work Rob.

  7. rafal’s avatar

    Thanks Gabriel, I overrode teardown method and now it works as supposed :)