1. Code
  2. Game Development

La guía para principiantes sobre los tests unitarios: creación de temas testables

En los dos primeros artículos de esta serie, echamos un vistazo de alto nivel a qué son los tests unitarios y cómo aplicarlos en el contexto del desarrollo de plugins. Por supuesto, hay más en WordPress que la creación de plugins, ¿no? Una parte significativa del trabajo de un desarrollador de WordPress, para algunos la parte más significativa, es el desarrollo de temas.
Scroll to top

Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)

En los dos primeros artículos de esta serie, echamos un vistazo de alto nivel a qué son los tests unitarios y cómo aplicarlos en el contexto del desarrollo de plugins. Por supuesto, hay más en WordPress que la creación de plugins, ¿no? Una parte significativa del trabajo de un desarrollador de WordPress, para algunos la parte más significativa, es el desarrollo de temas.

Así que en este artículo, vamos a echar un vistazo a cómo desarrollar temas testables. Específicamente, vamos a echar un vistazo a en qué se diferencian los temas de los plugins y luego vamos escribiremos un tema extremadamente simple que se utilizará para demostrar los principios de los tests unitarios y que se pueden aplicar en el desarrollo futuro.


Entender las diferencias entre los temas y los plugins

Antes de empezar a crear el tema o revisar ningún código, es importante entender las diferencias entre el desarrollo de temas y plugins. En primer lugar, los plugins pueden ser escritos de dos formas:

  • Como un objeto que encapsula un conjunto de funciones (que es lo que hemos hecho en este artículo).
  • Como una simple colección de funciones

Ambos métodos consiguen realizar lo mismo: es decir, usan una colección de funciones y filtros para introducir nuevas funcionalidades en WordPress. La diferencia principal es la forma en la que las funciones son encapsuladas.

Pero en lo que se refiere al desarrollo de temas, solo existe una forma de desarrollar un tema y se trata de usar una colección de funciones definidas en functions.php. Esto presenta los dos siguientes retos a la hora de escribir tests unitarios para los temas:

  • Porque el tema no está orientado a objetos, no tenemos ningún medio de almacenar realmente el objeto en una matriz tal y como hicimos en el último artículo
  • Debemos determinar una forma de escribir y evaluar las funciones de nuestro tema que puedan ejecutarse con independencia de la carga del mismo en un navegador

Dado que los buenos temas utilizan una colección de filtros y acciones, vamos a crear un tema que siga las aquellas mejores prácticas y como el énfasis de este artículo concreto reside en el testeo unitario de los temas, haremos mayor énfasis en la escritura de estos tests que en la creación de un tema con buena apariencia y altamente funcional.


Preparación para los tests unitarios

Antes de empezar a escribir código, empecemos a crear el directorio de nuestro proyecto. Tenemos que configurar el esqueleto de nuestro tema, de manera que en el directorio de nuestro tema de WordPress, crea un nuevo directorio para el mismo. El mío se denomina Basic-Theme. Añade los siguientes archivos (les añadiremos contenido más adelante):

  • footer.php
  • functions.php
  • header.php
  • index.php
  • style.css

Avancemos y empecemos con la hoja de estilos de manera que WordPress reconozca el tema y nos permita activarlo desde el escritorio. Para ello, añade el siguiente código al archivo style.css:

1
2
/*

3
Theme Name: Basic Theme

4
Theme URI: TODO

5
Version: 1.0

6
Description: A basic theme used to demonstrate how to write unit tests for themes.

7
Author: Tom McFarlin

8
Author URI: https://tommcfarlin.com

9
License: GNU General Public License v2.0

10
License URI: http://www.gnu.org/licenses/gpl-2.0.html

11
*/

Para completar, continúa y añade etiquetas PHP de apertura y cierre al principio y al final de tu archivo de funciones. Esto nos asegurará que tenemos hecho el trabajo de base para cuando empecemos a escribir las funciones del tema más adelante en este artículo.

Y añade un nuevo directorio denominado tests. Aquí, tendremos que colocar los tests de WordPress.


Tests de WordPress: Unas breves palabras

Con anterioridad en esta serie, proporcioné un enlace a los tests WordPress ubicados en GitHub. Aunque está bien utilizar estos tests, el más reciente, Automattic-maintained WordPress tests están localizados en este repositorio de Subversion.

Si eres un desarrollador avanzado, te recomiendo que eches un vistazo a esos tests; sin embargo, si estás empezando con los tests unitarios, ¡no es ningún problema! Estoy proporcionando todo el código fuente, incluyendo los tests unitarios de WordPress, en un repositorio de GitHub que podrás descargar, referenciar, y usar en tus propios proyectos.

Una vez instalados los temas, el directorio de tu tema debería tener el siguiente aspecto:

Basic ThemeBasic ThemeBasic Theme

Como PHPUnit debe ser ejecutado desde la línea de comandos, necesitarás abrir una sesión en la terminal (o una solicitud de comando), navegar al directorio de los tests, y deberías ser capaz de ejecutarlos usando los siguientes comandos (por ejemplo):

1
2
phpunit tests/test_user_capabilities.php

Tu terminal debería mostrar después algo como esto:

Basic ThemeBasic ThemeBasic Theme
Atención: si no eres capaz de ejecutar los tests, por favor, vuelve a consultar el primer artículo de esta serie para verificar tu configuración. Además, tu kilometraje podría variar según tu sistema operativo, tu servidor web, y la configuración de tu equipo local. Si terminas teniendo que hacer algo distinto, por favor, comparte tus anotaciones a través de un comentario para ayudar a otros.

Tema básico: un WordPress testable unitariamente

En este punto, avancemos y activemos el tema desde el Escritorio. El tema se debería activar (si no es así, asegúrate de no tener ningún carácter extraño en tus archivos de plantilla). Si intentas visualizar el tema, naturalmente verás una pantalla en blanco.

Antes de escribir cualquier test, continuemos e introduzcamos un poco de contenido en nuestros archivos de plantilla simplemente para tener algo mostrándose en el frontend.

En header.php, añade el siguiente código:

1
2
<!DOCTYPE html>
3
<html>
4
	<head>	
5
		<meta charset="UTF-8">
6
		<link rel="profile" href="http://gmpg.org/xfn/11" />
7
		<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
8
		<title><?php wp_title( '' ); ?></title>
9
		<?php wp_head(); ?>
10
	</head>
11
	<body <?php body_class(); ?>>
12
	
13
		<div id="header">
14
			This is the header.
15
		</div><!-- /#header -->

En index.php, añade el siguiente código:

1
2
<?php get_header(); ?>
3
4
	<div id="content">
5
		This is the content.
6
	</div><!-- /#content -->
7
8
<?php get_footer(); ?>

En footer.php, añade el siguiente código:

1
2
		<div id="footer">
3
			This is the footer.
4
		</div><!-- /#footer -->
5
6
	</body>
7
</html>

Simple, ya lo sé, pero esto nos proporcionará suficiente con lo que trabajar siempre que empecemos a escribir tests. Guarda tu trabajo, revisa el tema en el navegador y deberías ver algo como esto:

Basic ThemeBasic ThemeBasic Theme

Escribir tests unitarios

Activación del test del tema

En el directorio de tus tests, crea un archivo denominado test_basic_theme.php y modifica el archivo para que tenga el siguiente aspecto:

1
2
// Include the functions for the theme

3
include_once('../functions.php');
4
5
class Test_Basic_Theme extends WP_UnitTestCase {
6
	
7
} // end class

Arriba, estamos definiendo una clase que usaremos para envolver todas las unidades de tests de nuestro tema.

Primero, vamos a definir el método setUp. El método setUp es una función proporcionada por el framework de Tests de WordPress que podemos utilizar para desencadenar ciertas funciones antes de ejecutar los tests. Por ejemplo, cuando se ejecutan los Tests de WordPress, lo hacen sobre el tema predeterminado, es decir, sobre el tema Twenty Eleven.

En nuestro caso, queremos ejecutar los tests en nuestro propio tema. Para hacerlo, necesitaremos decirle a WordPress que cambie los temas antes de ejecutar el resto de nuestros tests. Dado que esto necesita tener lugar antes de la ejecución de los tests, debe ser definido en el método setUp. ¿Le encuentras sentido?

Así que vamos a escribir nuestro método setUp:

1
2
function setUp() {
3
	
4
	parent::setUp();
5
	switch_theme( 'Basic Theme', 'Basic Theme' );
6
	
7
} // end setup

De nuevo, ejecutemos nuestros tests. Podemos hacerlo ejecutando el mismo comando que utilizamos cuando configuramos inicialmente el test:

1
2
phpunit tests/test_basic_theme.php

Si has hecho todo correctamente, deberías ver realmente un fallo durante la ejecución del test:

Basic ThemeBasic ThemeBasic Theme

El mensaje de error es claro: "No se han encontrado tests en la clase "Test_Basic _Theme"". De modo que vamos a mitigar esto y a escribir el primer test para el tema. Puede ser algo extraordinariamente sencillo, pero recuerda que ya mencionamos en anterior artículo que no queremos comprobar solo la ruta óptima, sino también la ruta fallida.

Por tanto necesitamos comprobar que Basic Theme esté activo y que Twenty Eleven no lo esté. Para hacer esto, vamos a utilizar el método assertTrue y el método assertFalse, y lo haremos dentro del contexto de dos funciones. Echa un vistazo al siguiente código y actualiza el archivo de tu código en consecuencia:

1
2
function testActiveTheme() {
3
4
	$this->assertTrue( 'Basic Theme' == get_current_theme() );
5
	
6
} // end testThemeInitialization

7
8
function testInactiveTheme() {
9
10
	$this->assertFalse( 'Twenty Eleven' == get_current_theme() );
11
12
} // end testInactiveTheme

Nuevamente, ejecuta los tests, deberías verlos ejecutarse en verde. Genial ¿no?

Basic ThemeBasic ThemeBasic Theme

Esta es una funcionalidad relativamente simple, por lo tanto, vamos a considerar unas cuantas funciones avanzadas que podría tener nuestro tema.

Comprobar que jQuery está encolado

En principio, Basic Theme no incluye jQuery así que vamos a incluirlo en él. Si te acuerdas, en los artículos anteriores, la metodología de testeado unitario adecuada es como sigue:

  1. Escribir el test
  2. Ejecutar el test (que fallará)
  3. Escribir el código necesario para que el test lo pase
  4. Ejecutar el test (y debería pasar, si el Paso 3 fue realizado correctamente)

Así que hagamos exactamente esto para jQuery.

Primero, necesitamos escribir un test para determinar si jQuery se ha cargado. Estaremos usando la función de WordPress wp_script_is. Dado que el tema va a recorrer el habitual ciclo de página en un navegador, tendremos que indicarle manualmente a WordPress que cargue jQuery usando la función do_action.

1
2
function testjQueryIsLoaded() {
3
4
	$this->assertFalse( wp_script_is( 'jquery' ) );
5
6
	do_action( 'wp_enqueue_scripts' );
7
	$this->assertTrue( wp_script_is( 'jquery' ) );
8
9
} // end testjQueryIsLoaded

Antes de continuar, hay algo importante a advertir aquí: no me gusta colocar múltiples declaraciones en una única función porque creo que cada función debería servir para comprobar una única cosa; sin embargo, hay excepciones. Aquí, necesitamos asegurarnos de que jQuery no esté cargado antes de llamar a la función do_action.

En cualquier caso, ejecuta el test, fallará. Así que necesitamos añadir el código al archivo functions.php que se asegurará de que jQuery esté añadido en nuestro tema. Para conseguirlo, incluye la siguiente función en el archivo de funciones de tu tema:

1
2
function basic_add_jquery() {
3
4
	wp_enqueue_script( 'jquery' );	
5
	
6
} // end basic_remove_jquery

7
add_action( 'wp_enqueue_scripts', 'basic_add_jquery' );

Por último, ejecuta el test, debería aparecer en verde. Fácil, ¿no?

Comprobar las descripciones meta

Imagina que queremos incluir una descripción meta en la página de inicio. En su forma más simple, no será más que la descripción del blog. Así que, siguiendo nuestra metodología, introduzcamos una función para comprobar que la cadena de la descripción meta esté añadida al elemento de la cabecera coincida con lo que esperamos:

1
2
function testBasicMetaDescription() {
3
	
4
	$meta_description = '<meta name="description" content="' . get_bloginfo( 'description' ) . '" />';
5
	$this->expectOutputString( $meta_description, basic_meta_description() );
6
	
7
} // end testBasicMetaDescription

Ejecútalo, fallará. Observa que no estoy utilizando las funciones estándar assertTrueassertFalse, daremos más detalles sobre esto en un momento. Ahora, introduzcamos la siguiente función en nuestro archivo functions.php:

1
2
function basic_meta_description() {
3
	
4
	echo '<meta name="description" content="' . get_bloginfo( 'description' ) . '" />';
5
	
6
} // end basic_meta_description

7
add_action( 'wp_head', 'basic_meta_description' );

Observa que esta función está enganchada en la acción wp_head. Para escribir la descripción meta en el elemento head, debemos hacer eco de la cadena en lugar de devolverla.

Ahora, observa como en el anterior test estamos usando expectOutputString. Esto es útil cuando necesitamos evaluar una función que haga eco de una cadena (en lugar de devolverla). Dado que la acción wp_head va a devolver una significativa cantidad de datos (es decir, el elemento head completo), nosotros solo necesitamos comprobar la descripción meta devuelta. Y por eso, en lugar de llamar a do_action( ‘wp_head’ ), estoy invocando únicamente a la función en sí y evaluando la salida con respecto a lo que yo espero que contenga.

Una vez más, ejecuta PHPUnit y tus pruebas deberían pasar.


Compruébalo todo

Es evidente que solo hemos arañado la superficie de lo que los tests unitarios pueden contribuir en nuestro desarrollo de temas. Hay mucho más que puede ser testeado, ni siquiera hemos visto la comprobación del bucle, las distintas formas de evaluar los formatos de entradas, e incluso cómo examinar los comentarios.

Recuerda que esto es una guía de inicio y que los tres artículos cubren muchos fundamentos.

A pesar de todo, los principios son los mismos: es cuestión de que te asegures de disparar programáticamente la función o la acción apropiada y de evaluar su salida tanto en las situaciones esperadas como en las no esperadas.

Por último, puedes encontrar el proyecto completo junto con las funciones documentadas en este repositorio de GitHub.


Recursos

Aquí tienes un sumario de los recursos que he utilizado en este artículo: