KEMBAR78
Unit testing symfony plugins with php unit | PDF
Unit testing symfony plugins with PHPUnit


             Christian Schäfer
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



About myself
●
    nick: caefer
●
    34, married, two cats
●
    senior system architect at Gruner+Jahr in hamburg
●
    web developer for over 11 years
●
    symfony developer for over 3 years


●
    blogs daily on http://test.ical.ly
●
    tweets @testically
●
    experiments on github.com/caefer
●
    loves scottish whisky, british comedy and uncommon music
    and his wife and two cats obviously :)
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



What is your motivation?


• What is your main interest when developing plugins?
• Do you unit test your plugins?
• Who has worked with PHPUnit before?
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Defining the goals
When developing plugins you want to make sure they..


         • ..can be used stand-alone
         • ..can be installed easily
         • ..hold as little dependencies as possible*


         • ..work!




 *   where dependencies to symfony itself and Doctrine or Propel are only natural
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Prerequisites
In this talk I will be using the following:


       • symfony 1.4
       • PHPUnit 3.5
       • Hudson CI
       • sfTaskExtraPlugin


Always use sfTaskExtraPlugin when creating a new plugin!
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



A word about unit testing in symfony 1
lime works! ..but
      • Not too well documented
      • Not found outside symfony
      • Not easy to integrate in continuous integration servers


 Why I prefer PHPUnit instead
      • It's well documented
      • It's well distributed
      • It's the de factor standard in the PHP world
      • It's actively maintained
      • It can easily be integrated in Hudson, phpUnderControl,
        Bamboo, yourFavouriteCISoftware
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Getting started
Did I mention to use sfTaskExtraPlugin ?



Create a plugin with this command:


     $ php symfony generate:plugin csTicTacToePlugin


Then take a look at the files that were created.
Two things are of particular interest:


       • test/fixtures/project/*
       • test/bootstrap/unit.php
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



The fixture project
 The fixture project is a sandbox, a testing environment for your plugin.


• It is a fully working symfony project.
• You can even point a vHost to its web folder! (don't!)


• You can run symfony commands in it.*


• Add/remove/modify anything in it that your plugin requires of any
  project!
• Document everything you change.


 * beforehand: $ export SYMFONY=/path/to/your/symfony/lib/dir
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



The fixture project - todos
• Configure a database connection


      dsn: sqlite::memory:


• Generate your models


      $ php symfony doctrine:build ­­all­classes


• Enable modules if exist
• Create test fixtures in data/fixtures/
• Create local schema.yml if required for testing (i.e. for behaviours)
• Enable plugins if required by your plugin
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



The bootstrap
The bootstrapping process is responsible for firing up symfony and
all that is required for your tests.


This can include


      • Autoloading symfony
      • Enable required plugins (i.e. your own)
      • Autoloading project specific classes (i.e. model classes)
      • Database configuration
      • Rest of the configuration cascade
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



The bootstrap - todos
• Remove lime

 require_once $configuration­>getSymfonyLibDir().'/vendor/lime/lime.php';



• Adjust project configuration to your needs

 $projectPath = dirname(__FILE__).'/../fixtures/project';
 1. Generic project config → symfony paths, plugins, project autoloading, database, configuration cascade
 $configuration = new sfProjectConfiguration($projectPath);
 2. Fixture project config → symfony paths, plugins, project autoloading, database, configuration cascade
 require_once($projectPath.'/config/ProjectConfiguration.class.php');
 $configuration = new ProjectConfiguration($projectPath);
 3. Fixture application config → symfony paths, plugins, project autoloading, database, configuration cascade
 require_once($projectPath.'/config/ProjectConfiguration.class.php');
 $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true);
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Pre-configuring PHPUnit
With the 3.5 release using PHPUnit became much more convenient!


Create a phpunit.xml.dist for a default configuration and ship it
with your plugin. Users can create their own phpunit.xml which will
be prefered by PHPUnit if it exists.


      • 1. Configure bootstrap
      • 2. Configure the path to the symfony lib dir
      • 3. Configure the path to the unit tests
      • 4. Configure scope for the coverage report
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Pre-configuring PHPUnit - todos
1. Configure bootstrap
<phpunit … bootstrap="test/bootstrap/unit.php" … >
2. Configure the path to the symfony lib dir
  <php><server name="SYMFONY" value="../symfony/"/></php>
3. Configure the path to the unit tests
  <testsuites>
    <testsuite name="csTicTacToePlugin Suite">
      <directory>./test/unit/</directory>
    </testsuite>
  </testsuites>
4. Configure scope for the coverage report
  <filter>
    <whitelist addUncoveredFilesFromWhitelist="true">
      <directory suffix=".php">./lib/</directory>
      <directory suffix=".php">./config/</directory>
    </whitelist>
  </filter>
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Using the database
 Always initialize the database in your TestCases setUp() method!*


• Initialize the database manager
 new sfDatabaseManager(ProjectConfiguration::getActive());
• Create database
 Doctrine_Manager::getInstance()­>createDatabases('doctrine');
• Create all tables
 Doctrine_Core::createTablesFromModels(sfConfig::get('sf_lib_dir'));
• Create specific tables
 Doctrine_Core::createTablesFromArray(array('SomeRecord', ..));
• Load fixtures
 Doctrine_Core::loadData(sfConfig::get('sf_data_dir').'/fixtures/fixtures.
 yml')


 * This is Doctrine specific! Unfortunately I don't know how to do the following with Propel..
Christian Schäfer: Unit testing von symfony plugins with PHPUnit



Lets see an example
Here's a simple plugin for demonstration:
http://github.com/caefer/csTicTacToePlugin


Here are a few of my best practices:
      • Test every class in your config and lib folder.
      • Write one test case per class.
      • Mirror the directory structure in your test/unit folder.
      • Name you test case like the covered class postfixed with “Test”.


    config/csTicTacToePluginConfiguration.class.php
    lib/model/doctrine/PluginTicTacToe.class.php
    → test/unit/config/csTicTacToePluginConfiguration.class.php
    → test/unit/lib/model/doctrine/PluginTicTacToe.class.php
Christian Schäfer: Unit testing von symfony plugins with PHPUnit




      Questions anybody?
Christian Schäfer: Unit testing von symfony plugins with PHPUnit




             Cheers!
      ..now let's go to lunch.

Unit testing symfony plugins with php unit

  • 1.
    Unit testing symfonyplugins with PHPUnit Christian Schäfer
  • 2.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit About myself ● nick: caefer ● 34, married, two cats ● senior system architect at Gruner+Jahr in hamburg ● web developer for over 11 years ● symfony developer for over 3 years ● blogs daily on http://test.ical.ly ● tweets @testically ● experiments on github.com/caefer ● loves scottish whisky, british comedy and uncommon music and his wife and two cats obviously :)
  • 3.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit What is your motivation? • What is your main interest when developing plugins? • Do you unit test your plugins? • Who has worked with PHPUnit before?
  • 4.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Defining the goals When developing plugins you want to make sure they.. • ..can be used stand-alone • ..can be installed easily • ..hold as little dependencies as possible* • ..work! * where dependencies to symfony itself and Doctrine or Propel are only natural
  • 5.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Prerequisites In this talk I will be using the following: • symfony 1.4 • PHPUnit 3.5 • Hudson CI • sfTaskExtraPlugin Always use sfTaskExtraPlugin when creating a new plugin!
  • 6.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit A word about unit testing in symfony 1 lime works! ..but • Not too well documented • Not found outside symfony • Not easy to integrate in continuous integration servers Why I prefer PHPUnit instead • It's well documented • It's well distributed • It's the de factor standard in the PHP world • It's actively maintained • It can easily be integrated in Hudson, phpUnderControl, Bamboo, yourFavouriteCISoftware
  • 7.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Getting started Did I mention to use sfTaskExtraPlugin ? Create a plugin with this command: $ php symfony generate:plugin csTicTacToePlugin Then take a look at the files that were created. Two things are of particular interest: • test/fixtures/project/* • test/bootstrap/unit.php
  • 8.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit The fixture project The fixture project is a sandbox, a testing environment for your plugin. • It is a fully working symfony project. • You can even point a vHost to its web folder! (don't!) • You can run symfony commands in it.* • Add/remove/modify anything in it that your plugin requires of any project! • Document everything you change. * beforehand: $ export SYMFONY=/path/to/your/symfony/lib/dir
  • 9.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit The fixture project - todos • Configure a database connection dsn: sqlite::memory: • Generate your models $ php symfony doctrine:build ­­all­classes • Enable modules if exist • Create test fixtures in data/fixtures/ • Create local schema.yml if required for testing (i.e. for behaviours) • Enable plugins if required by your plugin
  • 10.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit The bootstrap The bootstrapping process is responsible for firing up symfony and all that is required for your tests. This can include • Autoloading symfony • Enable required plugins (i.e. your own) • Autoloading project specific classes (i.e. model classes) • Database configuration • Rest of the configuration cascade
  • 11.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit The bootstrap - todos • Remove lime require_once $configuration­>getSymfonyLibDir().'/vendor/lime/lime.php'; • Adjust project configuration to your needs $projectPath = dirname(__FILE__).'/../fixtures/project'; 1. Generic project config → symfony paths, plugins, project autoloading, database, configuration cascade $configuration = new sfProjectConfiguration($projectPath); 2. Fixture project config → symfony paths, plugins, project autoloading, database, configuration cascade require_once($projectPath.'/config/ProjectConfiguration.class.php'); $configuration = new ProjectConfiguration($projectPath); 3. Fixture application config → symfony paths, plugins, project autoloading, database, configuration cascade require_once($projectPath.'/config/ProjectConfiguration.class.php'); $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true);
  • 12.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Pre-configuring PHPUnit With the 3.5 release using PHPUnit became much more convenient! Create a phpunit.xml.dist for a default configuration and ship it with your plugin. Users can create their own phpunit.xml which will be prefered by PHPUnit if it exists. • 1. Configure bootstrap • 2. Configure the path to the symfony lib dir • 3. Configure the path to the unit tests • 4. Configure scope for the coverage report
  • 13.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Pre-configuring PHPUnit - todos 1. Configure bootstrap <phpunit … bootstrap="test/bootstrap/unit.php" … > 2. Configure the path to the symfony lib dir   <php><server name="SYMFONY" value="../symfony/"/></php> 3. Configure the path to the unit tests   <testsuites>     <testsuite name="csTicTacToePlugin Suite">       <directory>./test/unit/</directory>     </testsuite>   </testsuites> 4. Configure scope for the coverage report   <filter>     <whitelist addUncoveredFilesFromWhitelist="true">       <directory suffix=".php">./lib/</directory>       <directory suffix=".php">./config/</directory>     </whitelist>   </filter>
  • 14.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Using the database Always initialize the database in your TestCases setUp() method!* • Initialize the database manager new sfDatabaseManager(ProjectConfiguration::getActive()); • Create database Doctrine_Manager::getInstance()­>createDatabases('doctrine'); • Create all tables Doctrine_Core::createTablesFromModels(sfConfig::get('sf_lib_dir')); • Create specific tables Doctrine_Core::createTablesFromArray(array('SomeRecord', ..)); • Load fixtures Doctrine_Core::loadData(sfConfig::get('sf_data_dir').'/fixtures/fixtures. yml') * This is Doctrine specific! Unfortunately I don't know how to do the following with Propel..
  • 15.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Lets see an example Here's a simple plugin for demonstration: http://github.com/caefer/csTicTacToePlugin Here are a few of my best practices: • Test every class in your config and lib folder. • Write one test case per class. • Mirror the directory structure in your test/unit folder. • Name you test case like the covered class postfixed with “Test”. config/csTicTacToePluginConfiguration.class.php lib/model/doctrine/PluginTicTacToe.class.php → test/unit/config/csTicTacToePluginConfiguration.class.php → test/unit/lib/model/doctrine/PluginTicTacToe.class.php
  • 16.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Questions anybody?
  • 17.
    Christian Schäfer: Unittesting von symfony plugins with PHPUnit Cheers! ..now let's go to lunch.