El tutorial Jobeet

9.6. Escribiendo pruebas funcionales

Crear las pruebas funcionales es similar a ejecutar un determinado escenario en el navegador. En nuestro caso, las historias que escribimos para el tutorial del día 2 ya describen todos los escenarios que debemos probar.

En primer lugar vamos a probar la página principal de Jobeet mediante el archivo de pruebas jobActionsTest.php. Reemplaza su contenido por el siguiente código:

9.6.1. Las ofertas de trabajo expiradas no se muestran en el listado

// test/functional/frontend/jobActionsTest.php
include(dirname(__FILE__).'/../../bootstrap/functional.php');

$browser = new JobeetTestFunctional(new sfBrowser());
$browser->loadData();

$browser->info('1 - The homepage')->
  get('/')->
  with('request')->begin()->
    isParameter('module', 'job')->
    isParameter('action', 'index')->
  end()->
  with('response')->begin()->
    info('  1.1 - Expired jobs are not listed')->
    checkElement('.jobs td.position:contains("expired")', false)->
  end()
;

Como sucede en lime, puedes utilizar el método info() para mostrar mensajes informativos y hacer que la salida del programa sea más fácil de leer. Para comprobar que no se muestran ofertas de trabajo expiradas, comprobamos que el selector CSS .jobs td.position:contains("expired") no encuentra ningún elemento dentro del contenido HTML de la respuesta (recuerda que en los archivos de datos que utilizamos, la única oferta de trabajo expirada contiene el valor expired en el campo position). Si el segundo argumento del método checkElement() es un valor booleano, el método prueba si existen nodos que cumplan con ese selector CSS.

Nota El método checkElement() es capaz de interpretar correctamente la mayoría de selectores CSS3 válidos.

9.6.2. Sólo se muestran N ofertas de trabajo en el listado de cada categoría

Aañade el siguiente código al final del archivo de pruebas:

// test/functional/frontend/jobActionsTest.php
$max = sfConfig::get('app_max_jobs_on_homepage');

$browser->info('1 - The homepage')->
  get('/')->
  info(sprintf('  1.2 - Only %s jobs are listed for a category', $max))->
  with('response')->
    checkElement('.category_programming tr', $max)
;

Si el segundo argumento del método checkElement() es un número entero, el método prueba si existen N nodos que cumplan con ese selector CSS.

9.6.3. Las categorías muestran un enlace a la página de categoría sólo si tienen demasiadas ofertas de trabajo

// test/functional/frontend/jobActionsTest.php
$browser->info('1 - The homepage')->
  get('/')->
  info('  1.3 - A category has a link to the category page only if too many jobs')->
  with('response')->begin()->
    checkElement('.category_design .more_jobs', false)->
    checkElement('.category_programming .more_jobs')->
  end()
;

En este caso comprobamos que no se muestre un enlace llamado "more jobs" en la categoría design (es decir, que no exista .category_design .more_jobs) y que se muestre un enlace llamado "more jobs" en la categoría programming (es decir, que exista .category_programming .more_jobs).

9.6.4. Las ofertas de trabajo se ordenan cronológicamente

// most recent job in the programming category
$criteria = new Criteria();
$criteria->add(JobeetCategoryPeer::SLUG, 'programming');
$category = JobeetCategoryPeer::doSelectOne($criteria);

$criteria = new Criteria();
$criteria->add(JobeetJobPeer::EXPIRES_AT, time(), Criteria::GREATER_THAN);
$criteria->add(JobeetJobPeer::CATEGORY_ID, $category->getId());
$criteria->addDescendingOrderByColumn(JobeetJobPeer::CREATED_AT);

$job = JobeetJobPeer::doSelectOne($criteria);

$browser->info('1 - The homepage')->
  get('/')->
  info('  1.4 - Jobs are sorted by date')->
  with('response')->begin()->
    checkElement(sprintf('.category_programming tr:first a[href*="/%d/"]', $job->getId()))->
  end()
;

Para probar que las ofertas de trabajo se ordenan cronológicamente, comprobamos que la primera oferta de trabajo del listado de la portada es la oferta que esperamos. Por tanto, debemos comprobar que la URL contiene el valor que esperamos para la clave primaria. Además, como la clave primaria puede cambiar de una ejecución a otra, en primer lugar debemos obtener el objeto Propel de la base de datos.

Aunque la prueba anterior ya funciona correctamente, vamos a refactorizar su código para poder reutilizar en otras pruebas la lógica que obtiene la primera oferta de trabajo de la categoría programming. Como se trata de un código específico para pruebas, en este caso no vamos a moverlo a la capa del modelo, sino que vamos a colocarlo en la clase JobeetTestFunctional que hemos creado anteriormente. De esta forma, esta clase actúa como una clase de pruebas funcionales específicas para el dominio de Jobeet.

// lib/test/JobeetTestFunctional.class.php
class JobeetTestFunctional extends sfTestFunctional
{
  public function getMostRecentProgrammingJob()
  {
    // most recent job in the programming category
    $criteria = new Criteria();
    $criteria->add(JobeetCategoryPeer::SLUG, 'programming');
    $category = JobeetCategoryPeer::doSelectOne($criteria);

    $criteria = new Criteria();
    $criteria->add(JobeetJobPeer::EXPIRES_AT, time(), Criteria::GREATER_THAN);
    $criteria->add(JobeetJobPeer::CATEGORY_ID, $category->getId());
    $criteria->addDescendingOrderByColumn(JobeetJobPeer::CREATED_AT);

    return JobeetJobPeer::doSelectOne($criteria);
  }

  // ...
}

Ahora puedes reemplazar el código de la prueba anterior por el siguiente código:

// test/functional/frontend/jobActionsTest.php
$browser->info('1 - The homepage')->
  get('/')->
  info('  1.4 - Jobs are sorted by date')->
  with('response')->begin()->
    checkElement(sprintf('.category_programming tr:first a[href*="/%d/"]',
      $browser->getMostRecentProgrammingJob()->getId()))->
  end()
;

9.6.5. Cada oferta de trabajo de la portada incluye un enlace

$browser->info('2 - The job page')->
  get('/')->

  info('  2.1 - Each job on the homepage is clickable and give detailed information')->
  click('Web Developer', array(), array('position' => 1))->
  with('request')->begin()->
    isParameter('module', 'job')->
    isParameter('action', 'show')->
    isParameter('company_slug', 'sensio-labs')->
    isParameter('location_slug', 'paris-france')->
    isParameter('position_slug', 'web-developer')->
    isParameter('id', $browser->getMostRecentProgrammingJob()->getId())->
  end()
;

Para probar el enlace que muestra cada oferta de trabajo de la portada, simulamos que hemos pinchado sobre el texto "Web Developer". Como en la página existen muchos enlaces con ese texto, le pedimos al navegador de forma explícita que pinche sobre el primero que encuentre (array('position' => 1)).

A continuación se prueban los parámetros de la petición para asegurarnos que el sistema de enrutamiento ha funcionado correctamente.