Pruebas simples con PHPUnit en Local WP

Pensaba que escribir pruebas simples con PHPUnit para WordPress era algo complicado de hacer, incluso en entornos con Laravel o paquetes de PHP. Estaba equivocado.

Las pruebas simples con PHPUnit para WordPress son fáciles de escribir, y por lo tanto, fácil de probar nuestro código para evitar problemas a futuro.

Comúnmente, cuando hacemos pruebas de nuestros temas y plugins, solemos ir al navegador, abrir nuestro entorno WordPress y ver si la funcionalidad se ejecuta de manera adecuada.

Aunque lo anterior es válido, no siempre podremos identificar errores dentro de la funcionalidad esperada.

Por eso, escribir pruebas PHPUnit para WordPress es la mejor opción para evitar errores y darte la confianza de que tu código está funcionando adecuadamente.

Pruebas PHPUnit para WordPress

Las pruebas para WordPress, y cualquier otro proyecto, existen dentro de la carpeta /tests y cada archivo debe tener el siguiente formato:

test-<filename-to-test>.php

Cuando digo <filename-to-test> significa que debes escribir el nombre del archivo al cual le estás haciendo un test.

Por ejemplo, si estás escribiendo pruebas para el archivo class-wp-phpunit-pe-simple.php entonces el nombre de archivo de tu test será test-class-wp-phpunit-pe-simple.php.

El prefijo test- puede ser cambiado dentro del archivo phpunit.xml.dist, por ejemplo, si quieres que los archivos sean testing-class-wp-phpunit-pe-simple.php tu configuración de PHPUnit sería:

<testsuites>
   <testsuite name="wp-phpunit-plugin-example">
      <directory prefix="testing-" suffix=".php">./tests/</directory>
   </testsuite>
</testsuites>

Ya que tengas tu archivo de prueba creado, crearás la clase y métodos que se ejecutarán para probar tu código y funcionalidad.

La clase WP_UnitTestCase

El punto más importante es heredar la clase WP_UnitTestCase en tu clase de prueba, por ejemplo, si estás creando la clase WP_PHPUnit_PE_Simple_Test, la clase luciría así:

<?php

class WP_PHPUnit_PE_Simple_Test extends WP_UnitTestCase {
   // Contenido de la clase.
}

Ahora puedes crear los métodos para probar tu código y funcionalidad ya que la clase WP_UnitTestCase incluye los métodos necesarios para probar alguna funcionalidad específica de WordPress.

Para los métodos de prueba, estos deben empezar con el prefijo test_, casi parecido a como lo hicimos con el nombre del archivo anterior. Los métodos que empiecen con test_ serán ejecutados por PHPUnit.

Un método de prueba (ya dentro de la clase de prueba) luce así:

<?php

class WP_PHPUnit_PE_Simple_Test extends WP_UnitTestCase {
   private $post;

   public function test_change_post_title() {
      $this->assertSame( 'My name is Roel', get_the_title( $this->post ) );
   }
}

El método setUp()

Otro método que vamos a usar mucho en nuestras clases de pruebas es setUp(). Este método siempre se ejecuta antes de ejecutar cada prueba. Y aquí, comúnmente, se ejecutarán los objetos de prueba (factories) e instancias de nuestras clases reales.

Si tienes dos métodos que empiezan con test_, quiere decir que tienes dos pruebas y se ejecutará dos veces el método setUp(). Un ejemplo sería:

<?php

class WP_PHPUnit_PE_Simple_Test extends WP_UnitTestCase {
   private $post;

   /**
    * Initialize the WP_PHPUnit_PE_Simple class to register the
    * filters hooks to change the post title.
    */
   public function setUp() {
      $this->post = $this->factory->post->create_and_get( array(
         'post_title'   => 'My name is your_name',
         'post_content' => 'Hello, this is a custom post content for PHPUnit testing...',
      ) );

      new WP_PHPUnit_PE_Simple();
   }

   public function test_change_post_title() {
      $this->assertSame( 'My name is Roel', get_the_title( $this->post ) );
   }
}

En este post no veremos los métodos o aserciones que nos brinda PHPUnit por default, sin embargo, la clase WP_UnitTestCase nos da las siguientes aserciones que servirán para probar algunas funciones de WordPress:

  • assertEqualSets()
  • assertWPError()
  • assertNotWPError()

¿Qué son los factories?

Los factories crean objetos de prueba, por ejemplo, si quieres crear un usuario dinámicamente en tus pruebas, un factory de usuario es la solución.

En nuestro caso, nos servirán para crear posts dinámicamente desde el método setUp(). Si estás haciendo pruebas con usuarios, también hay un factory para usuarios.

La clase WP_UnitTestCase nos provee algunos factories para crear objetos:

  • Adjuntos.
  • Comentarios.
  • Posts.
  • Categorías, Tags y Terms.
  • Usuarios.

Un ejemplo para crear un post usando factory puede ser en dos formas, una donde solo crea el post y otra donde crea el post y lo retorna:

// Solo crea el post.
$this->factory->post->create( $post );

// Crea el post y retorna el mismo como WP_Post.
$this->factory->post->create_and_get( $post );

Comúnmente, los factories serán usados dentro del método setUp() y luce así:

/**
 * Initialize the WP_PHPUnit_PE_Simple class to register the
 * filters hooks to change the post title.
 */
public function setUp() {
   $this->post = $this->factory->post->create_and_get( array(
      'post_title'   => 'My name is your_name',
      'post_content' => 'Hello, this is a custom post content for PHPUnit testing...',
   ) );

   new WP_PHPUnit_PE_Simple();
}

Dentro del método, el post creado será guardará en una propiedad, de esta forma, se usará en diferentes métodos.

Para nuestro plugin de ejemplo, WP PHPUnit Plugin Example, he dividido las pruebas en tres secciones: Simples, API REST y AJAX.

Las siguientes pruebas las puedes encontrar en el repositorio del proyecto de prueba, dentro de la rama plugin_with_tests.

Pruebas Simples

Empezamos con las pruebas simples, estas pruebas se encuentran en el archivo tests/test-class-wp-phpunit-pe-simple.php y hace las siguientes pruebas:

  • Compara si el título del post creado es igual al que especificamos.
  • Checa si el post creado contiene un enlace que agregamos usando un filtro.

El archivo principal que usaremos será el includes/class-wp-phpunit-pe-simple.php y ejecuta los siguientes filtros:

add_filter( 'the_title', array( $this, 'change_post_title' ) );

public function change_post_title( $title ) {
   return str_replace( 'your_name', 'Roel', $title );
}

El filtro the_title ejecuta nuestro método change_post_title el cual reemplaza la palabra your_name con el nombre de Roel de nuestro post.

¿A qué post nos referimos? ¿Recuerdas el método setUp()? Lo usaremos para crear un post dinámicamente, para eso, utilizaremos el factory post que nos provee la clase WP_UnitTestCase:

/**
 * Initialize the WP_PHPUnit_PE_Simple class to register the
 * filters hooks to change the post title.
 */
public function setUp() {
   $this->post = $this->factory->post->create_and_get( array(
      'post_title'   => 'My name is your_name',
      'post_content' => 'Hello, this is a custom post content for PHPUnit testing...',
   ) );

   new WP_PHPUnit_PE_Simple();
}

Ahora si podemos escribir nuestra primera prueba, ubicada en el archivo tests/test-class-wp-phpunit-pe-simple.php:

public function test_change_post_title() {
   $this->assertSame( 'My name is Roel', get_the_title( $this->post ) );
}

Estamos probando si el texto “My name is Roel” es igual al título obtenido por la función get_the_title( $this->post ). Recuerda que $this->post es definida en el método setUp().

Cuando se ejecuta la función get_the_title() también se ejecutará el filtro que hemos especificado en nuestro archivo includes/class-wp-phpunit-pe-simple.php dando como resultado final “My name is Roel“.

Si ejecutas la prueba desde PHPStorm, verás que la prueba ha pasado correctamente:

Pruebas para WordPress Plugins Simples
Pruebas para WordPress Plugins Simples.

Ahora podemos escribir la segunda prueba:

public function test_insert_new_link() {
   $permalink = get_permalink( $this->post );
   $this->go_to( $permalink );

   ob_start();
   the_content();
   $post_content = ob_get_clean();

   $this->assertContains( '<p><a href="https://roelmagdaleno.com">https://roelmagdaleno.com</a></p>', $post_content );
}

La prueba anterior nos probará si el contenido del post creado contiene un párrafo y un enlace que lleva a mi sitio web.

La funcionalidad es parecida a la primera prueba. Debemos definir el filtro adecuado para agregar el enlace a mi sitio web; eso lo hacemos con el siguiente código dentro del archivo includes/class-wp-phpunit-pe-simple.php:

add_filter( 'the_content', array( $this, 'insert_new_link' ) );

public function insert_new_link( $content ) {
	$content .= '<p><a href="https://roelmagdaleno.com">https://roelmagdaleno.com</a></p>';
	return $content;
}

Usaremos el filtro the_content para adjuntar (.=) dinámicamente un párrafo con mi sitio web para después retornar el contenido del post.

Procede a realizar la prueba, y fíjate que es algo diferente, encontrarás una función y un método:

$permalink = get_permalink( $this->post );
$this->go_to( $permalink );

La función get_permalink() sirve para obtener el enlace del post creado anteriormente y el método $this->go_to(), internamente, te “redireccionará” al enlace que especifiques en el primer parámetro.

Después puedes obtener el contenido del post renderizado con el siguiente código donde usamos ob_start() y ob_get_clean():

ob_start();
the_content();
$post_content = ob_get_clean();

Aunque pudiese haber otras formas de obtener el contenido del post, he decidido usar esta manera para usar el método $this->go_to().

Ahora si puedes ejecutar la aserción (prueba) para ver si el contenido del post es de acuerdo al esperado:

$this->assertContains( '<p><a href="https://roelmagdaleno.com">https://roelmagdaleno.com</a></p>', $post_content );

Te invito a que ejecutes la prueba con PHPStorm o desde tu terminal. Deberías ver un resultado exitoso y si te sale un resultado erróneo, entonces la respuesta no fue la esperada (si es así trata de resolverlo).

Continúa con las Pruebas API REST con PHPUnit en Local WP.

Roel Magdaleno
Escrito por Roel Magdaleno

Roel Magdaleno es un ingeniero informático especializado en desarrollo web desde hace más de 5 años. Desarrolla sitios web, aplicaciones web, plugins para WordPress y scripts con PHP y JavaScript. Además, comparte su conocimiento en su blog personal.

Deja un comentario