El tutorial Jobeet

8.8. Pruebas unitarias para Propel

8.8.1. Configuración de la base de datos

Escribir pruebas unitarias para la clase de un modelo es un poco más complicado porque requiere una conexión con la base de datos. Aunque ya disponemos de la conexión que configuramos para el entorno de desarrollo, es una buena práctica crear una conexión con la base de datos específica para las pruebas.

Durante el tutorial del primer día explicamos el concepto de entornos de ejecución como una forma sencilla de modificar las opciones con las que se ejecuta una aplicación. Por defecto, las pruebas se ejecutan en un entorno llamado test, por lo que vamos a configurar una base de datos diferente para este entorno test:

$ php symfony configure:database --env=test "mysql:host=localhost;dbname=jobeet_test" root ConTraSenA

La opción env le indica a la tarea configure:database que esta conexión con la base de datos sólo se emplea en el entorno test. Cuando utilizamos esta tarea en el tutorial del día 3, no pasamos ninguna opción env, por lo que la configuración se realizó para todos los entornos.

Nota Si sientes curiosidad, abre el archivo de configuración config/databases.yml para ver lo fácil que es en Symfony modificar la configuración en función del entorno.

Después de configurar la base de datos, podemos inicializarla mediante la tarea propel:insert-sql:

$ mysqladmin -uroot -pConTraSenA create jobeet_test
$ php symfony propel:insert-sql --env=test

8.8.2. Datos para pruebas

Ahora que ya tenemos una base de datos sólo para pruebas, tenemos que llenarla con datos de prueba. Durante el día 3 aprendimos a utilizar la tarea propel:data-load, pero en las pruebas es necesario volver a cargar los datos cada vez que ejecutamos las pruebas para conocer el estado inicial de la base de datos. La tarea propel:data-load utiliza internamente la clase sfPropelData para cargar los datos:

$loader = new sfPropelData();
$loader->loadData(sfConfig::get('sf_test_dir').'/fixtures');

Nota El objeto sfConfig se puede utilizar para obtener la ruta completa hasta un subdirectorio del proyecto. Utilizando este método se puede modificar la estructura de directorios por defecto de Symfony.

El método loadData() acepta como primer argumento el nombre de un directorio o un archivo. Este método también admite un array de directorios y/o archivos.

Los días anteriores ya creamos algunos datos de pruebas que guardamos en el directorio data/fixtures/. Los archivos de datos para pruebas los vamos a guardar en el directorio test/fixtures/. Estos archivos de datos los va a utilizar Propel para las pruebas unitarias y funcionales.

Por el momento, copia los archivos del directorio data/fixtures/ al directorio test/fixtures/.

8.8.3. Probando JobeetJob

A continuación vamos a crear pruebas unitarias para la clase del modelo JobeetJob.

Como todas nuestras pruebas unitarias relacionadas con Propel empiezan con las mismas líneas de código, crea un archivo llamado propel.php en el directorio bootstrap/ de las pruebas y que contenga el siguiente código:

// test/bootstrap/propel.php
include(dirname(__FILE__).'/unit.php');

$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true);

new sfDatabaseManager($configuration);

$loader = new sfPropelData();
$loader->loadData(sfConfig::get('sf_test_dir').'/fixtures');

El script anterior es bastante sencillo de entender:

  • Como sucede en los controladores frontales, inicializamos un objeto de tipo configuración para el entorno test:
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true);
  • Creamos un gestor de bases de datos e inicializamos la conexión Propel cargando el archivo de configuración databases.yml.
new sfDatabaseManager($configuration);
  • Cargamos los datos de prueba mediante sfPropelData:
$loader = new sfPropelData();
$loader->loadData(sfConfig::get('sf_test_dir').'/fixtures');

Nota Propel sólo se conecta con la base de datos si existen sentencias SQL pendientes de ejecutar.

Ahora que ya tenemos todo preparado, podemos empezar a probar la clase JobeetJob.

En primer lugar, crea el archivo JobeetJobTest.php en test/unit/model:

// test/unit/model/JobeetJobTest.php
include(dirname(__FILE__).'/../../bootstrap/propel.php');

$t = new lime_test(1, new lime_output_color());

A continuación, creamos una prueba unitaria para el método getCompanySlug():

$t->comment('->getCompanySlug()');
$job = JobeetJobPeer::doSelectOne(new Criteria());
$t->is($job->getCompanySlug(), Jobeet::slugify($job->getCompany()), '->getCompanySlug() return the slug for the company');

Como puedes observar en el código anterior, sólo estamos probando el método getCompanySlug() y no si el slug generado es correcto o no, porque eso ya lo hemos probado en otras pruebas.

Crear una prueba para el método save() es un poco más complicado:

$t->comment('->save()');
$job = create_job();
$job->save();
$expiresAt = date('Y-m-d', time() + 86400 * sfConfig::get('app_active_days'));
$t->is($job->getExpiresAt('Y-m-d'), $expiresAt, '->save() updates expires_at if not set');

$job = create_job(array('expires_at' => '2008-08-08'));
$job->save();
$t->is($job->getExpiresAt('Y-m-d'), '2008-08-08', '->save() does not update expires_at if set');

function create_job($defaults = array())
{
  static $category = null;

  if (is_null($category))
  {
    $category = JobeetCategoryPeer::doSelectOne(new Criteria());
  }

  $job = new JobeetJob();
  $job->fromArray(array_merge(array(
    'category_id'  => $category->getId(),
    'company'      => 'Sensio Labs',
    'position'     => 'Senior Tester',
    'location'     => 'Paris, France',
    'description'  => 'Testing is fun',
    'how_to_apply' => 'Send e-Mail',
    'email'        => '[email protected]',
    'token'        => rand(1111, 9999),
    'is_activated' => true,
  ), $defaults), BasePeer::TYPE_FIELDNAME);

  return $job;
}

Nota Cada vez que añades nuevas pruebas, no te olvides de actualizar en el constructor del método lime_test el número de pruebas que esperas realizar. En el archivo JobeetJobTest tienes que reemplazar el valor 1 original por 3.

8.8.4. Probando otras clases de Propel

Ahora ya puedes probar otras clases de Propel. Como poco a poco te estás acostumbrando a crear pruebas unitarias, no será muy complicado escribir esas pruebas.