Ver índice de contenidos del libro

10.3. Tests funcionales

Los tests funcionales verifican el funcionamiento conjunto de diversas partes de la aplicación (desde el sistema de enrutamiento hasta la parte de la vista). Aunque en lo que respecta a PHPUnit no son muy diferentes a los tests unitarios, en la práctica su flujo de trabajo es muy diferente:

  • Hacer una petición.
  • Comprobar la respuesta recibida.
  • Pinchar sobre un enlace o enviar un formulario.
  • Dejar todo como estaba y volver a probar otras funcionalidades.

10.3.1. Tu primer test funcional

Las tests funcionales son archivos PHP que suelen encontrarse en el directorio Tests/Controller/ de tu bundle. Si deseas probar las páginas gestionadas por la clase DemoController, empieza creando un nuevo archivo llamado DemoControllerTest.php que extienda de una clase especial llamada WebTestCase.

La edición estándar de Symfony2 proporciona por ejemplo un test funciona sencillo para la clase DemoController con el siguiente contenido:

// src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php
namespace Acme\DemoBundle\Tests\Controller;
 
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
 
class DemoControllerTest extends WebTestCase
{
    public function testIndex()
    {
        $client = static::createClient();
 
        $crawler = $client->request('GET', '/demo/hello/Fabien');
 
        $this->assertGreaterThan(
            0,
            $crawler->filter('html:contains("Hello Fabien")')->count()
        );
    }
}

Truco Para ejecutar los tests funcionales, la clase WebTestCase necesita ejecutar el núcleo de tu aplicación. En la mayoría de los casos, esto sucede automáticamente. Sin embargo, si tu núcleo se encuentra en un directorio no estándar, deberás modificar el archivo phpunit.xml.dist para ajustar la variable de entorno KERNEL_DIR al directorio de tu núcleo:

<phpunit>
    <!-- ... -->
    <php>
        <server name="KERNEL_DIR" value="/path/to/your/app/" />
    </php>
    <!-- ... -->
</phpunit>

El método createClient() devuelve un cliente, que es algo parecido a un navegador con el que puedes acceder a cualquier página de tu sitio web:

$crawler = $client->request('GET', '/demo/hello/Fabien');

El método request() devuelve un objeto de tipo Crawler que puedes utilizar para extraer elementos o trozos de la respuesta, pinchar enlaces, y enviar formularios.

Truco El Crawler sólo funciona cuando la respuesta es XML o HTML. Para obtener el contenido original de la respuesta recibida del servidor, utiliza el método $client->getResponse()->getContent().

Para pinchar sobre un enlace, selecciónalo primero con el Crawler utilizando una expresión XPath o un selector CSS, y utilizando después el cliente para pinchar sobre él. El siguiente ejemplo muestra el código necesario para buscar todos los enlaces que contengan el texto Greet y a continuación, pincha sobre el segundo de esos enlaces:

$link = $crawler->filter('a:contains("Greet")')->eq(1)->link();
 
$crawler = $client->click($link);

Enviar un formulario es un proceso similar: selecciona un botón del formulario, opcionalmente reemplaza algunos valores del formulario, y ​​por último, envía el formulario:

$form = $crawler->selectButton('submit')->form();
 
// sustituye algunos valores
$form['name'] = 'Lucas';
$form['form_name[subject]'] = 'Hey there!';
 
// envía el formulario
$crawler = $client->submit($form);

Truco El formulario también permite subir archivos y contiene métodos para rellenar diferentes tipos de acmpos (por ejemplo, select() y tick()). Para más detalles, consulta la sección Formularios más adelante.

Ahora que ya puedes navegar fácilmente a través de una aplicación, utiliza los asserts para comprobar que la aplicación hace realmente lo que se espera. Utiliza el Crawler para definir los asserts sobre el DOM de las páginas:

// Comprueba el contenido de la página utilizando selectores de CSS
$this->assertGreaterThan(0, $crawler->filter('h1')->count());

También puedes probar el contenido original de la respuesta si lo que deseas es comprobar que el contenido contiene algún texto, o si la respuesta no es un documento XML o HTML:

$this->assertRegExp(
    '/Hello Fabien/',
    $client->getResponse()->getContent()
);

Para facilitarte el trabajo, a continuación te indicamos varios ejemplos de asserts comunes en los tests funcionales de las aplicaciones Symfony2:

use Symfony\Component\HttpFoundation\Response;
 
// ...
 
// Asegura que existe al menos una etiqueta <h2>
// con la clase 'subtitle' de CSS
$this->assertGreaterThan(
    0,
    $crawler->filter('h2.subtitle')->count()
);
 
// Asegura que hay exactamente 4 etiquetas <h2> en la página
$this->assertCount(4, $crawler->filter('h2'));
 
// Asegura que la cabecera 'Content-Type' es 'application/json'
$this->assertTrue(
    $client->getResponse()->headers->contains(
        'Content-Type',
        'application/json'
    )
);
 
// Asegura que el contenido de la respuesta cumple con una expresión regular
$this->assertRegExp('/foo/', $client->getResponse()->getContent());
 
// Asegura que el código de estado de la respuesta es 2xx
$this->assertTrue($client->getResponse()->isSuccessful());
 
// Asegura que el código de estado de la respuesta es 404
$this->assertTrue($client->getResponse()->isNotFound());
 
// Asegura que el código de estado es exactamente 200
$this->assertEquals(
    Response::HTTP_OK,,
    $client->getResponse()->getStatusCode()
);
 
// Asegura que la respuesta es una redirección a '/demo/contact'
$this->assertTrue(
    $client->getResponse()->isRedirect('/demo/contact')
);
 
// Asegura que la respuesta es una redirección a cualquier URL
$this->assertTrue($client->getResponse()->isRedirect());