Cómo testear una aplicación PHP que no usa objetos

PHPUnit, al igual que la mayoría de los frameworks de testing, se basa fuertemente en el supuesto de que la aplicación a verificar está desarrollada bajo el paradigma de Orientación a Objetos.

Sin embargo, es muy común en nuestros días encontrarnos con aplicaciones tipo spaghetti… ¿es posible hacer testing automatizado sobre ellas?

La respuesta es sí.

Claro que las respuestas a qué testear y cómo testear son un poco diferentes.

Qué puede testearse en una aplicación que no usa objetos

Obviamente, no será posible verificar una clase porque… la aplicación no tiene clases.

De modo que podemos testear:

  • La página que se presentará al usuario (Lo que podríamos asemejar a un test funcional)
  • El resultado de ejecutar alguna función en particular
  • El resultado de correr algún script

Cómo testear el resultado de una página php

Para este escenario nos tendremos que valer de un pequeño truco: las funciones ob_start y ob_get_clean (Además de tener instalado phpUnit, claro).

La idea es muy simple en realidad.

Se crea un caso de test, se abre un buffer y se incluye el archivo que queremos validar.

A continuación se levantan los contenidos del buffer y se examinan usando assertions.

Veamos un ejemplo simple:

El archivo que queremos validar se llama wrong.php

<html>
<body>
<p><?php echo 'Bye bye world'; ?></p>
</body>
</html>

Y este sería el caso de test:

<?php

use PHPUnit\Framework\TestCase;

class PageTest extends TestCase
{
        public function testGreeting()
        {
                ob_start();
                require_once 'wrong.php';
                $this->assertRegExp('/<p>Hello World!<\/p>/', ob_get_clean());
        }
}

Para correr el test usamos el comando vendor/bin/phpunit PageTest.php y la salida será:

PHPUnit 9.3.7 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 00:00.004, Memory: 4.00 MB

There was 1 failure:

1) PageTest::testGreeting
Failed asserting that '<html>\n
<body>\n
	<p>Bye bye world</p>\n
</body>\n
</html>\n
' matches PCRE pattern "/<p>Hello World!<\/p>/".

/home/mauro/Code/testing/PageTest.php:11

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

Cómo testear el resultado de una función php

Este caso es bastante similar al anterior, aunque un poco más simple.

Aquí lo que haremos será, en lugar de validar la salida completa, verificaremos qué sucedió como resultado de ejecutar la función.

Empecemos por modificar el archivo a testear:

<?php

function duplicate(int $p) : int
{
        return $p * 3;
}

Y ahora hagamos un nuevo test:

<?php

use PHPUnit\Framework\TestCase;

class FunctionTest extends TestCase
{
        public function testFunction()
        {
                ob_start();
                require_once 'wrong.php';

                $this->assertEquals(4, duplicate(2));
        }
}

El resto sigue igual al caso anterior

Cómo testear la ejecución de un script php

Por último, podríamos requerir testear el funcionamiento de un script de línea de comandos (Un cronjob por ejemplo).

Imaginemos un script como este:

<?php

echo 'Bye bye '.$argv[1].'!';

Y este test:

<?php

use PHPUnit\Framework\TestCase;

class ScriptTest extends TestCase
{
        public function testGreeting()
        {
                $this->assertEquals('Hello World!', shell_exec('php script.php World'));
        }
}

Nos dará este resultado:

PHPUnit 9.3.7 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 00:00.026, Memory: 4.00 MB

There was 1 failure:

1) ScriptTest::testGreeting
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Hello World!'
+'Bye bye World!'

/home/mauro/Code/testing/ScriptTest.php:9

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

Conclusión

En defintiva, no es cierto que es imposible testear aplicaciones php que no se basen en POO… lo que sí es cierto es que los tests van a ser más engorrosos y menos informativos.

Claro que eso es consecuencia de un diseño poco modular de la aplicación que estamos testeando… ¡pero esa fue precisamente la premisa del ejercicio!

Espero te haya dado alguna idea nueva, ¡espero tus comentarios!

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

2 comentarios

  1. Primero que nada, muchas felicidades por tu blog.
    Me fué de gran ayuda para darme una idea de como realizar test unitarios a codigo de php estruvturado.

    Tengo una duda, si necesito pasar arametros al archivo como si fuera una petición http (GET, POST) como podria hacerlo?
    Estuve investigando acerca del tema pero no encontré información.

    1. Hola Marcos:

      Gracias por tu comentario, me alegra haberte sido de ayuda.

      Respecto de la pregunta, se me ocurre que algo que podrías hacer es manipular en forma directa los arreglos POST y GET.

      Algo así como:

      $_GET['parametro'] = "un valor";
      require_once 'archivo_a_testear.php';

      Saludos,

¿Te quedó alguna duda? Publica aca tu pregunta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.