Tutorial Jobeet con Symfony2 Día 8: Pruebas unitarias

De WikiSalud
Saltar a: navegación, buscar
Este artículo es parte del proyecto Tutorial Jobeet con Symfony2

Contenido

Pruebas en Symfony2

Hay dos diferentes tipos de pruebas automatizadas en symfony: Test unitarios y Test funcionales. Test Unitarios verifican que cada método y funcionalidad esta trabajando apropiadamente. Cada test debe ser tan independiente como sea posible de otros. Por otro lado, test funcionales verifican que las aplicaciones resultantes se comporten correctamente como un todo

Los test unitarios serán cubiertos en este post, mientras que el próximo será dedicado a los test funcionales

Symfony2 se integra con una librería independiente, PHPUnit, para ofrecerte un nutrido framework de pruebas. Para correr pruebas tendràs que instalar PHPUnit 3.5.11 o superior

Cada prueba, si es un test unitario o uno funcional, es una clase PHP que debería estar en el subdirectorio Tests/ de tus bundles. Si tu sigues esta regla, entonces puedes llamar todos los test de tus aplicaciones con el siguiente comando:

phpunit -c app/

La opción -c le dice a PHPUnit que busque en el directorio app/ por un archivo de configuración. Si estas interesando en las opciones de PHPUnit, revisa el archivo app/phpunit.xml.dist

Pruebas unitarias

Usualmente, una prueba unitaria es una prueba contra una clase PHP especifica. Empecemos escribiendo test para el método Jobeet::slugify() Crear una nuevo archivo JobeetTest.php, en el folder src/Ens/JobeetBundle/Tests/Utils. Por convención, el subdirectorio Test/ debería resplicar el directorio de tu bundle. Así, cuando estamos testeando una clase en el directorio Utils/ de nuestros bundle's, colocamos las pruebas en el directorio Test/Utils/

src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
// src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
 
namespace Ens\JobeetBundle\Tests\Utils;
use Ens\JobeetBundle\Utils\Jobeet;
 
class JobeetTest extends \PHPUnit_Framework_TestCase
{
  public function testSlugify()
  {
    $this->assertEquals('sensio', Jobeet::slugify('Sensio'));
    $this->assertEquals('sensio-labs', Jobeet::slugify('sensio labs'));
    $this->assertEquals('sensio-labs', Jobeet::slugify('sensio   labs'));
    $this->assertEquals('paris-france', Jobeet::slugify('paris,france'));
    $this->assertEquals('sensio', Jobeet::slugify('  sensio'));
    $this->assertEquals('sensio', Jobeet::slugify('sensio  '));
  }
}

Para ejecutar solo esta prueba puedes usar el siguiente comando:

phpunit -c app/ src/Ens/JobeetBundle/Tests/Utils/JobeetTest

Como todo debería trabajar bien, deberías obtener el siguiente resultado:

PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /home/dragos/work/jobeet/app/phpunit.xml.dist

.

Time: 0 seconds, Memory: 3.50Mb

OK (1 test, 6 assertions)

Para una lista completa de funciones assertions, puedes revisar la documentación de PHPUnit

Añadiendo Pruebas unitarias para nuevas características

El slug para una cadena vacía es una cadena vacía. Tu puedes probar esto, funcionará. Pero una cadena vacía en una URL no es una gran idea. Vamos a cambiar el método slugify() de manera que retorne la cadena "n-a" en caso de una cadena vacía:

Tu puedes escribir el test primero, luego actualizar el método, o viceversa. Es realmente cuestión de gusto, pero escribir el test primero te da la confianza que tu codigo realmente implemente lo que has planeado

src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
// src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
// ...
 
$this->assertEquals('n-a', Jobeet::slugify(''));
 
// ...


Ahora, si corremos el test de nuevo, tendremos un fallo:

PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /home/dragos/work/jobeet/app/phpunit.xml.dist

F

Time: 0 seconds, Memory: 3.50Mb

There was 1 failure:

1) Ens\JobeetBundle\Tests\Utils\JobeetTest::testSlugify
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'n-a'
+

/home/dragos/work/jobeet/src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php:17

FAILURES!
Tests: 1, Assertions: 7, Failures: 1.

Ahora, editamos la clase Jobeet y añadimos la siguiente condición al inicio:

src/Ens/JobeetBundle/Utils/Jobeet.php
// src/Ens/JobeetBundle/Utils/Jobeet.php
// ...
 
static public function slugify($text)
{
  if (empty($text))
  {
    return 'n-a';
  }
 
// ...
}


La prueba debe pasar ahora según lo esperado, y puedes disfrutar de la barra verde.

Añadiendo Pruebas unitarias debido a un Bug

Digamos que el tiempo ha pasado y uno de tus usuarios reporta una extraño bug: Algunos ofertas de trabajo apuntan a una página de error 404. Después de investigar un poco, encuentras que por alguna razón estos ofertas tienen un slug compañía, posición o localidad

Como es posible Miras a tráves de los registros en la base de datos y definitivamente las columnas no están vacías. Piensas sobre ello por un tiempo, y bingo, encuentras la causa. Cuando una cadena contiene solo caracteres no-ASCII, el método slugify() lo convierte a una cadena vacía. Tan feliz de haber encontrado la causa, abres la clase Jobeet y solucionas el problema de inmediante. Pero es una mala idea. Primero, añadamos un Test

src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
// src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
$this->assertEquals('n-a', Jobeet::slugify(' - '));


Después de checar que la prueba no pasa, edita la clase Jobeet y mueve la comprobación de cadena vacía al final del método:

src/Ens/JobeetBundle/Tests/JobeetTest.php
static public function slugify($text)
{
  // ...
 
  if (empty($text))
  {
     return 'n-a';
  }
 
  return $text;
}


Ahora el nuevo test pasa, así como todos los otros. El método slugify tenía un bug a pesar de nuestro cobertura de 100%

No puedes pensar sobre todos los casos límites y escribir pruebas, y eso esta bien. Pero cuando tu descubres uno, necesitas escribir una prueba para él antes de reparar tu código. También significa que tu código sera mejor con el tiempo, lo cual siempre es algo bueno.

Hacia un mejor método slugify

Probablemente sepas que Symfony ha sido creado por gente francesa, así que agreguemos un prueba con una palabra frances que contenga un acento

src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
$this->assertEquals('developpeur-web', Jobeet::slugify('Développeur Web'));


El test debe fallar, En lugar de reemplazar é por e, el método slugify ha sido reemplazado por un guión (-). Eso es un problema dificil, llamado transliteración. Si tienes instalada la librería iconv, hará todo el trabajo por nosotros. Reemplaza el código del método slugify con el siguiente:

src/Ens/JobeetBundle/Utils/JobeetTest.php
static public function slugify($text)
{
  // replace non letter or digits by -
  $text = preg_replace('#[^\\pL\d]+#u', '-', $text);
 
  // trim
  $text = trim($text, '-');
 
  // transliterate
  if (function_exists('iconv'))
  {
    $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
  }
 
  // lowercase
  $text = strtolower($text);
 
  // remove unwanted characters
  $text = preg_replace('#[^-\w]+#', '', $text);
 
  if (empty($text))
  {
    return 'n-a';
  }
 
  return $text;
}


Recuerda guardar todos tus archivos PHP codificados con UTF-8, de esta forma es la codificación por defecto en symfony, y el usado por iconv para hacer la transliteración

Cambia también el archivo de test par correr el test solo si iconv esta disponible:

src/Ens/JobeetBundle/Tests/Utils/JobeetTest.php
if (function_exists('iconv'))
{
  $this->assertEquals('developpeur-web', Jobeet::slugify('Développeur Web'));
}

Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas