Monthly Archives: March 2011

Collecting CodeCoverage from symfony lime Tests

symfony-plugins-coverage

Since i use PHPUnit to test my symfony Applications and doing all automated stuff with Jenkins, i lost control over my lime test (e.g. in my plugins).
My Plugins stay in some kind of blackbox (lime isnt very useful with CI tools like Jenkins)

I love the Coverage Reports from PHPUnit (which is using PHP_CodeCoverage for that), which outputs me HTML or Clover, just as i need them.

To achieve the same with all my lime tests, i wrote a simple symfony plugin which, replaces the defaults “test:” tasks of symfony with my own modifed tasks.
Internally i extended the LimeHarness to use PHP_CodeCoverage for its reports:

Here is the Plugin https://github.com/digitalkaoz/rsPHPUnitLimePlugin

simply clone it or install it via pear or use svn.

Git: https://github.com/digitalkaoz/rsPHPUnitLimePlugin.git

Svn: https://svn.github.com/digitalkaoz/rsPHPUnitLimePlugin.git

PEAR: symfony plugins:install rsPHPUnitLimePlugin

After that you can use the tasks the same way (they have i slightly other name and some more options)

Usage

unit test coverage

  • symfony test:phpunit-unit –coverage-clover=log/clover-unit.xml
  • symfony test:phpunit-unit –coverage-html=log/coverage-unit
  • symfony test:phpunit-unit –coverage-folder=lib/
  • symfony test:phpunit-unit –xml=log/junit-unit.xml

functional test coverage

  • symfony test:phpunit-functional –coverage-clover=log/clover-functional.xml frontend
  • symfony test:phpunit-functional –coverage-html=log/coverage-functional frontend
  • symfony test:phpunit-functional –coverage-folder=apps/ frontend
  • symfony test:phpunit-functional –xml=log/junit-functional.xml frontend

plugin test coverage

  • symfony test:phpunit-plugin –coverage-clover=log/clover-functional.xml sfGuardPlugin
  • symfony test:phpunit-plugin –coverage-html=log/coverage-functional sfGuardPlugin
  • symfony test:phpunit-plugin –coverage-folder=plugin/sfGuardPlugin sfGuardPlugin
  • symfony test:phpunit-plugin –xml=log/junit-functional.xml sfGuardPlugin

all test coverage

  • symfony test:phpunit-all –coverage-clover=log/clover-functional.xml
  • symfony test:phpunit-all –coverage-html=log/coverage-functional sfGuardPlugin
  • symfony test:phpunit-all –coverage-folder=./
  • symfony test:phpunit-all –xml=log/junit-functional.xml

They work the same way as before, but they use PHP_CodeCoverage. You get nice HTML Reports and or Clover Reports.

To connect all your Plugin Tests with your default lime tests, simply modify your ProjectConfiguration:

 

  /**
   * reconfigure plugins
   */
  public function setupPlugins()
  {
    if(sfConfig::get('env') == 'prod')
    {
      return;
    }
    $plugins = sfFinder::type('directory')->name('*Plugin*')->maxdepth(0)->in(dirname(__FILE__).'/../plugins');
    $blackList = array('swFunctionalTestGenerationPlugin');
    foreach($plugins as $plugin)
    {
      $plugin = substr($plugin, strripos($plugin, DIRECTORY_SEPARATOR)+1);
      if(isset($this->pluginConfigurations[$plugin]) && !in_array($plugin,$blackList))
      {
        //connect the tests
        $this->pluginConfigurations[$plugin]->connectTests();
      }
    }
  }

To integrate this tests into your Jenkins Jobs simply use following build-step (as allways) :

export SYMFONY=$WORKSPACE/lib/vendor/symfony/lib
cd $WORKSPACE
./symfony test:phpunit-unit --xml=log/junit-results-plugin.xml --coverage-html=doc/coverage-plugin/ --coverage-clover=log/clover-report-plugin.xml --coverage-folder=plugins/

This will test all your unit tests, and writes the coverage to html and clover
in your post-build-actions simply publish your coverage data

Voila, now you can monitor your oldskool lime tests, or your plugins. It works with unit,functional and all test tasks

my first symfony2 Bundle “ProjectUtilitiesBundle”

Provides some more RAD symfony2 utilities

Features

  • Bootstrapper run commands defined in a yaml file to bootstrap an application
  • BundleLoader configure your Bundles in a yaml file
  • Configurator configures your application with private variables ie. database credentials 

Installation

Add ProjectUtilitiesBundle to your src/ dir

$ git submodule add git://github.com/digitalkaoz/ProjectUtilitiesBundle.git src/rs/ProjectUtilitiesBundle
$ git submodule init

Add the rs namespace to your autoloader

// app/autoload.php
$loader->registerNamespaces(array(
    'rs' => __DIR__.'/../src',
    // your other namespaces
);

Add ProjectUtilitiesBundle to your application kernel

 // app/AppKernel.php
 public function registerBundles()
 {
     return array(
         // ...
         new rs\ProjectUtilitiesBundle\ProjectUtilitiesBundle(),
         // ...
     );
 }
//or use the BundleLoader (see below)

Using DependencyInjection

$this->get('bootstrap');    //returns the bootstrapper
$this->get('configurator'); //returns the configurator
$this->get('bundleloader'); //returns the bundleloader
#app/config/config.yml
project_utilities:
  bootstrap:
    class: Bootstrapper
    file: app/config/bootstrap.yml
  bundleloader:
    class: Bundleloader
    file: app/config/bundles.yml
  configurator:
    class: Configurator
    setup: app/config/configuration.yml
    dist: .dist #the file extension for placeholder files
    config: /home/YOU/.[KERNEL.NAME]_[KERNEL.ENVIRONMENT].ini #private vars

TODO

  • more tests
  • more sophisticated dic

Bootstrapper

the bootstrapper builds an app with console and commands

configure your commands:

# app/config/project_bootstrap.yml
commands:
  - 'doctrine:generate:entities FooBundle'
  - 'doctrine:schema:update'
  - 'help'
shells:
  - 'ls'

run the command

# with the default config
$ app/console project:bootstrap
# with a custom config
$ app/console project:bootstrap --config=~/foo.yml
# stop if a command fails
$ app/console project:bootstrap --stop

BundleLoader

the BundleLoader manages your bundle config in an yaml file

use the BundleLoader in your Application Kernel

// app/AppKernel.php
use rs\ProjectUtilitiesBundle\Project\BundleLoader;
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $file = $this->getRootDir().'/config/bundles.yml';
        return BundleLoader::loadFromFile($file,$this->getEnvironment());
    }
}

environment configurations

# app/config/bundles.yml
all:
  - Symfony\Bundle\FrameworkBundle\FrameworkBundle
  - Symfony\Bundle\TwigBundle\TwigBundle
  - Symfony\Bundle\ZendBundle\ZendBundle
  - Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle
  - rs\ProjectUtilitiesBundle\ProjectUtilitiesBundle
dev:
  - Symfony\Bundle\DoctrineBundle\DoctrineBundle
test:

Configurator

the configurator stores your private variables in a file
it replaces placeholders within your files with those variables

define the configuration

# app/config/configuration.yml
in_dirs:
  - config
  - views
in_files:
  - bootstrap_%%KERNEL.ENViRONMENT%%.php
variables:
  DB_NAME:
    desc: database name
    default: symfony_%%KERNEL.ENVIRONMENT%%
  DB_PWD:
    desc: database password
    default: symfony
  DB_USER:
    desc: database user
    default: symfony
  DB_HOST:
    desc: database host
    default: localhost

use the following placeholder format (file format doesnt matter):

#app/config/config.yml.dist
doctrine:
 dbal:
   dbname:   %%DB_NAME%%
   user:     %%DB_USER%%
   password: %%DB_PWD%%

all files with extension .dist will be parsed and replaced with tokens!

these .dist files can be stored in your vcs

dont check in password or private configurations

(when the configurator runs it creates placeholder replaced copies without the .dist extension)

run the command

# with the default config (/home/YOU/.[KERNEL.NAME]_[KERNEL.ENVIRONMENT].ini)
$ app/console project:configure
# list current config variables
$ app/console project:configure --list
# lists current setup
$ app/console project:configure --setup