Seguimos la serie de post sobre patrones de testing utilizando PHPUnit. Ya hemos visto muchos patrones y también muchas formas de afrontar los testa cuando tenemos que testear código legacy. Aunque si bien es cierto, la mejor manera de testear este código legacy es apoyarse en el refactor automático de los IDE y en la cautela.
Esta vez vamos ha tratar unos patrones más para poder testear aplicaciones. Así que adelante.
Layer test
Muchas aplicaciones web de hoy en día utilizan una arquitectura en capas, por ejemplo una capa de infraestructura (persistencia de datos), una capa de servicio y una capa de presentación (para manejar el HTML).
El patrón Layer test se basa en escribir tests independientes para cada capa de la aplicación. Parece algo lógico, pero mantener test aislados es una tarea difícil. La mejor manera de mantener esa separación es tener pocos tests que cubran la mayor parte de la funcionalidad.
En el siguiente ejemplo veremos como probar una clase Render utilizando un script PHP.
En este caso, utilizando un pequeño scrip mantendremos separadas toda la vista con su HTML, CSS y JS del Controlador.
Este es el script, con el solo imprimimos las variables que vamos a utilizar en el render
<h1><?php echo $this->name; ?></h1>
description); ?>
Este es el test justo con la clase Render
<?php
class PresentationLayerTest extends PHPUnit_Framework_TestCase
{
public function testHtmlOutputConformsToExpectedOne()
{
$render = new Render(array(
'name' => 'Jesus',
'description' => 'Computer engineer who <3 PHP'
));
$content = $render->render('layertest.php');
$expected = <<<EOT
<h1>Jesus</h1>
Computer engineer who
EOT;
$this->assertEquals($expected, $content);
}
}
class Render
{
/**
* @var array
*/
private $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function render($file)
{
ob_start();
include $file;
$content = ob_get_contents();
ob_end_clean();
return $content;
}
public function __get($name)
{
return $this->data[$name];
}
}
Service Stub
Escribir test en los que intervienen recursos externos a veces es un fastidio, ya que no siempre están disponibles esos recursos y además hacen que los tests sean lentos.
Una manera de mejorar la arquitectura de nuestra aplicación es utilizar interfaces Gateway las cuales sirvan de punto de unión entere el sistema externo y nuestra aplicación.
Un Gateway es una fina capa de abstracción, la cual es el punto de unión entre nuestro sistema y el exterior, así partes internas de nuestro sistema pueden interactuar con el gateway sin saber si utilizan el servicio real o un simulador.
Por ejemplo, tenemos un componente que interactua con twitter y trae los tweets de un usuario, por ello nuestro gateway tendrá un método getLastTweet que dado un usuario devuelve los últimos tweets. Aquí tenemos nuestro Service Stub en marcha
class TwitterGatewayStub
{
public function __construct($tweetToReturn)
{
$this->text = $tweetToReturn;
}
public function getLastTweet($username)
{
assert('$username == "jeslopcru"');
return $this->text;
}
}
class SomeClientClassUnitTest extends PHPUnit_Framework_TestCase
{
public function testSomeFeatureOfTheClientClass()
{
// automatically generated Service Stub
$twitterMock = $this->getMock('TwitterGateway');
$twitterMock->expects($this->once())
->method('getLastTweet')
->with('jeslopcru')
->will($this->returnValue('A Tweet...'));
// or
// $twitterMock = new TwitterGatewayStub('A Tweet');
// $client = new ClientClass($twitterMock);
// proceed with the test...
}
}
Así podemos testear todo lo que necesitemos de nuestro componente sin conectarnos directamente a Twitter.
Conclusiones
Estos patrones nos ayudan a mejorar nuestro diseño, no solo hacen que la aplicación vaya más fluida, sino que además es mucho más fácil hacer cambios y comprobar que hay un bug, pero los tests unitarios no son la panacea, necesitamos también test de integración de carga,…
Antes de terminar esta serie de post me gustaría recomendar una serie post de DZone del usuario http://css.dzone.com/users/piccoloprincipe, con ellos he aprendido mucho sobre patrones de Test, también existen muchos libros sobre testing que nos dan consejos sobre como afrontar los tests en PHP. Bueno en realidad casi cualquier lenguaje es válido, ya que algunos de estos patrones que hemos comentado están sacados de libro Test Driven cuyos ejemplos están en Java.
2 comentarios en “patrones de test, mejorando la arquitectura en PHP”