Ponga en marcha sus pruebas de PHP con Codeception

Publicado: 2022-03-11

Antes de pasar a Codeception y PHP, debemos cubrir los conceptos básicos y comenzar explicando por qué necesitamos probar las aplicaciones en primer lugar. ¿Quizás podríamos completar un proyecto sin perder tiempo en pruebas, al menos esta vez?

Claro, no necesitas pruebas para todo; por ejemplo, cuando desea crear otra página de inicio. Probablemente no necesite pruebas cuando su proyecto contiene páginas estáticas vinculadas por un enrutador.

Sin embargo, definitivamente necesita pruebas cuando:

  • Su equipo usa BDD/TDD.
  • Su repositorio de Git contiene más de un par de confirmaciones.
  • Eres un buen profesional, trabajando en un proyecto serio.

Puede disculparse diciendo que ya tiene un departamento de pruebas dedicado, un grupo de personas que realizan pruebas y escriben otras nuevas cuando es necesario. Pero, ¿te imaginas cuánto tiempo tardará la corrección de errores después de agregar una nueva funcionalidad a tu proyecto?

¿Qué resuelve la prueba?

Primero, decidamos qué tipo de problemas pueden resolverse mediante pruebas. No puede deshacerse de todos sus errores con las pruebas, pero puede describir el comportamiento esperado en los casos de prueba. Los errores pueden estar dentro de sus casos de prueba. El código espagueti sigue siendo código espagueti incluso cuando usa casos de prueba.

Sin embargo, puede estar seguro de que su código se cambiará después (mediante la corrección de errores o la adición de nuevas funciones), por lo que su código seguirá estando libre de errores descritos en la prueba. Además, incluso las pruebas bien escritas a veces se pueden usar en la documentación porque allí puede ver cómo se desarrollan los escenarios típicos y verificar el comportamiento esperado. Podemos decir que las pruebas son una inversión pequeña pero crucial en el futuro.

Entonces, ¿qué tipo de pruebas podemos emplear?

Las pruebas unitarias básicas generalmente no son suficientes. Deben estar respaldados por pruebas de integración, funcionales y de aceptación.

Las pruebas unitarias básicas generalmente no son suficientes. Deben estar respaldados por pruebas de integración, funcionales y de aceptación.
Pío
  • Pruebas unitarias: pruebas de bajo nivel que verifican pequeñas partes de su código: los métodos de su clase aislados de otro código.
  • Pruebas de integración: las pruebas de integración verifican una parte de su aplicación, pueden contener varias clases o métodos, pero deben estar restringidas a una característica. Esta prueba también debe verificar cómo interactúan las diferentes clases.
  • Pruebas funcionales: prueba solicitudes específicas a su aplicación: respuesta del navegador, cambios en la base de datos, etc.
  • Pruebas de aceptación: en la mayoría de los casos, las pruebas de aceptación significan verificar si la aplicación cumple con todos los requisitos del cliente.

Para aclarar, digamos que ilustramos el proceso con algo tangible, como un edificio. Un edificio se compone de pequeños bloques que forman paredes. Cada ladrillo tiene que cumplir requisitos específicos; tiene que soportar la carga requerida, tener un volumen y forma específicos, etc. Estas son pruebas unitarias. La idea de las pruebas de integración es comprobar con qué firmeza y precisión se adhieren los ladrillos entre sí, cómo se integran en un determinado elemento del edificio. Las pruebas funcionales se pueden comparar con las pruebas en una sola pared del edificio, para comprobar si el interior está protegido de la intemperie o no, y si es posible ver el sol a través de la ventana. Las pruebas de aceptación implican probar todo el edificio como un producto completo: Abra la puerta, entre, cierre la puerta, encienda la luz, suba al segundo piso y eche un vistazo al jardín fuera del edificio.

Conozca a Codeception

Sin embargo, esta división es condicional ya veces es difícil resistir la tentación de mezclar distintos tipos de pruebas.

Muchos desarrolladores usan pruebas unitarias y afirman que eso es suficiente. Yo solía ser uno de esos desarrolladores; Encontré el uso de diferentes sistemas para diferentes tipos de pruebas demasiado difícil y lento. Hace un tiempo, decidí buscar algo más útil que PHPUnit; Quería ser mejor probando mi código, pero no quería leer y aprender toneladas de documentación y buscar trampas. Así es como descubrí Codeception. Al principio, era escéptico, como solemos ser cuando se trata de algo nuevo (este proyecto tiene cinco años, por lo que técnicamente no puede considerarse "nuevo"), pero después de jugar con él durante un par de días , concluí que Codeception es un sistema muy útil y poderoso.

Entonces, ¿cómo se instala Codeception? Es tan simple como se pone:

 $ composer require "codeception/codeception" $ php vendor/bin/codecept bootstrap

Después de la instalación, encontrará una nueva carpeta llamada pruebas en su proyecto, y habrá algunas subcarpetas llamadas aceptación, funcional y unidad . Parece que podemos empezar a escribir nuestras pruebas. Genial, pero ¿qué sigue?

Ahora, intente agregar una prueba de aceptación estándar Hello World.

 $ php vendor/bin/codecept generate:cept acceptance HelloWorld

Ahora, obtenemos un archivo de prueba de aceptación tests/acceptance/HelloWorldCept.php, con el siguiente contenido:

 <?php $I = new AcceptanceTester($scenario); $I->wantTo('perform actions and see result');

La variable predeterminada, llamada $I , no es solo una letra; es un personaje ¿Qué lleva a cabo las pruebas? El probador, obviamente. Este probador abre la página o clase de su sitio web, hace algo con ella y le muestra el resultado final de sus acciones. Verás lo que funcionó y lo que salió mal. Es por eso que este objeto se llama $I y contiene métodos llamados wantTo() , see() o amOnPage() .

Entonces, pensemos como lo haría un probador sobre las formas de verificar la operatividad de una página. El primer enfoque es abrir la página y buscar una frase. Demuestra que la página está disponible para los visitantes.

Esto debería ser fácil:

 <?php $I->amOnPage('/'); $I->see('Welcome');

Podemos usar este comando para ejecutar las pruebas de Codeception:

 $ php vendor/bin/codecept run

Inmediatamente vemos que algo anda mal. A primera vista, parece que el mensaje es demasiado largo y poco claro, pero cuando miramos más de cerca, todo se vuelve obvio.

¡Vaya! Algo salió mal. Ese es el objetivo de las pruebas. Revise el mensaje, identifique el error y aprenda de sus errores.

¡Vaya! Algo salió mal. Ese es el objetivo de las pruebas. Revise el mensaje, identifique el error y aprenda de sus errores.
Pío

Tuvimos una prueba, Aceptación , y detectó un error:

 Acceptance Tests (1) Perform actions and see result (HelloWorldCept) Error ---------- 1) Failed to perform actions and see result in HelloWorldCept (tests/acceptance/HelloWorldCept .php) [GuzzleHttp\Exception\ConnectException] cURL error 6: Could not resolve host: localhost (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

Este es el culpable: localhost no está disponible.

Y aquí están los pasos del escenario de nuestra prueba:

 1. $I->amOnPage("/")

Ok, abramos tests/acceptance.suite.yml y cambiemos url: http://localhost/ a algo que esté realmente disponible. En mi caso, es mi host de prueba local, url: https://local.codeception-article.com/

Vuelva a ejecutar la prueba y esto es lo que debe terminar con:

 Acceptance Tests (1) --------------------------------------------------------------------------------------- Perform actions and result (HelloWorldCept) Ok

¡Hurra! ¡Nuestra primera prueba exitosa!

Por supuesto, amOnPage() no es el único método de prueba disponible, simplemente lo seleccionamos para nuestro ejemplo. Todos los métodos de prueba de Codeception se pueden dividir en los siguientes grupos:

  • Interacción con la página: fillField() , selectOption() , submitForm() , click()
  • Afirmaciones. see() , dontSee() , seeElement() , seeInCurrentUrl() , seeCheckboxIsChecked() , seeInField() , seeLink() . A todos estos métodos puede agregar un sufijo y usarlo cuando necesite un método que no interrumpa el escenario de prueba cuando no se puede encontrar algo.
  • Métodos de cookies: setCookie() , grabCookie() , seeCookie()
  • Comentario y descripción de los escenarios de prueba: amGoingTo() , wantTo() , expect() . Utilice estos métodos para obtener pruebas bien comentadas y descritas, lo que le ayudará a recordar los objetivos de la prueba.

Entonces, si tuviéramos que probar la página de correo electrónico de restablecimiento de contraseña, podríamos hacerlo de esta manera:

 <?php $I = new AcceptanceTester($scenario); $I->wantTo('Test forgotten password functionality'); $I->amOnPage('/forgotten') $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link not sent for incorrect email'); $I->see('Email is incorrect, try again'); $I->amGoingTo('Fill correct email and get link'); $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link sent for correct email'); $I->see('Please check your email for next instructions');

Parece que esto debería funcionar, pero ¿qué pasa si hay algunas partes cargadas con Ajax en la página? ¿Podemos probar una página como esa? La respuesta es que Codeception usa PhpBrowser, basado en Symfony BrowserKit y Guzzle, por defecto. Es simple, rápido y solo necesitas curl para usarlo.

También puede usar Selenium y páginas de prueba con navegadores reales. Sí, será más lento, pero también podrá probar JavaScript.

Primero, debe instalar el controlador Selenium, cambiar accept.suite.yml y reconstruir la clase AcceptanceTester. Después de esto, puede usar los métodos wait() y waitForElement() . Y, lo que es más interesante, podrá ahorrar tiempo y recursos utilizando los métodos saveSessionSnapshot() y loadSessionSnapshot() . Este método le permite almacenar el estado de la sesión e iniciar nuevas pruebas en sesiones anteriores. Esto es útil en algunas situaciones, por ejemplo, en el proceso de autorización de pruebas.

Entonces, terminamos con una capacidad simple pero poderosa para probar muchas funciones.

Pruebas funcionales

Bien, es hora de pasar a las pruebas funcionales.

 $ php vendor/bin/codecept generate:cept functional HelloWorld

Y esto es lo que obtenemos:

 <?php $I = new FunctionalTester($scenario); $I->amOnPage('/'); $I->see('Welcome');

¿Esperar lo?

No, no es un error. Las pruebas funcionales deben escribirse de la misma manera que las pruebas de integración. La diferencia es que las pruebas funcionales interactúan directamente con su aplicación. Eso significa que no necesita un servidor web para ejecutar la prueba funcional y tiene más capacidad para probar diferentes partes de su aplicación.

Significa que falta soporte para todos los marcos, pero la lista de marcos compatibles es extensa: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel. Esto debería ser suficiente para la mayoría de los casos y la mayoría de los desarrolladores. Consulte la documentación del módulo de Codeception para obtener una lista de las funciones disponibles y luego enciéndalo en functional.suite.yml .

Codeception es compatible con los principales marcos: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel.

Codeception es compatible con los principales marcos: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel.
Pío

Antes de proceder con las pruebas unitarias, permítanme hacer una pequeña digresión. Como habrás notado, creamos nuestras pruebas con el concepto clave:

 $ php vendor/bin/codecept generate: cept acceptance HelloWorld

Esta no es la única manera de crear pruebas. También hay pruebas de cest . La diferencia es que puede estructurar múltiples escenarios relacionados en una clase:

 $ php vendor/bin/codecept generate:cest acceptance HelloWorld <?php class HelloWorldCest { public function _before(AcceptanceTester $I) { $I->amOnPage('/forgotten') } public function _after(AcceptanceTester $I) { } // tests public function testEmailField(AcceptanceTester $I) { $I->see('Enter email'); } public function testIncorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Email is incorrect, try again'); } public function testCorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Please check your email for next instructions'); } }

En este ejemplo, los métodos _before() y _after() se ejecutan antes y después de cada prueba. Se pasa una instancia de la clase AcceptanceTester a cada prueba, por lo que puede usarla de la misma manera que en las pruebas cest. Este estilo de pruebas puede ser útil en ciertas situaciones, por lo que vale la pena tenerlo en cuenta.

Examen de la unidad

Tiempo para algunas pruebas unitarias.

Codeception se basa en PHPUnit, por lo que puede usar pruebas escritas para PHPUnit. Para agregar nuevas pruebas de PHPUnit, use el siguiente enfoque:

 $ php vendor/bin/codecept generate:phpunit unit HelloWorld

O simplemente herede sus pruebas en \PHPUnit_Framework_TestCase .

Pero si quieres algo más, deberías probar las pruebas unitarias de Codeception:

 $ php vendor/bin/codecept generate:test unit HelloWorld <?php class HelloWorldTest extends \Codeception\TestCase\Test { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testUserSave() { $user = User::find(1); $user->setEmail('[email protected]'); $user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); } }

Nada inusual por ahora. Los métodos _before() y _after() son análogos a setUp() y tearDown() y se ejecutarán antes y después de cada prueba.

La principal ventaja de esta prueba es su capacidad para extender su proceso de prueba al incluir módulos que se pueden activar en unit.suite.yml :

  • Acceso a Memcache y bases de datos para realizar un seguimiento de los cambios (se admiten MySQL, SQLite, PostgreSQL, MongoDB)
  • Pruebas de aplicaciones REST/SOAP
  • Colas

Cada módulo tiene sus propias características, por lo que es mejor consultar la documentación y recopilar la información necesaria para cada módulo antes de proceder a las pruebas reales.

Además, puede usar el paquete Codeception/Specify (que debe agregarse a composer.json ) y escribir una descripción como esta:

 <?php class HelloWorldTest extends \Codeception\TestCase\Test { use \Codeception\Specify; private $user; protected function _before() { $this->user = User::find(1); } public function testUserEmailSave() { $this->specify("email can be stored", function() { $this->user->setEmail('[email protected]'); $this->user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); }); } }

El código PHP dentro de estas funciones de cierre está aislado, por lo que los cambios internos no afectarán el resto de su código. Las descripciones lo ayudarán a hacer que la prueba sea más legible y facilitará la identificación de las pruebas fallidas.

Como extra opcional, puede usar el paquete Codeception\Verify para una sintaxis similar a BDD:

 <?php public function testUserEmailSave() { verify($map->getEmail())->equals('[email protected]'); }

Y, por supuesto, puedes usar stubs:

 <?php public function testUserEmailSave() { $user = Stub::make('User', ['getEmail' => '[email protected]']); $this->assertEquals('[email protected]', $user->getEmail()); }

Veredicto: Codeception ahorra tiempo y esfuerzo

Entonces, ¿qué debe esperar de Codeception? ¿Para quién es? ¿Hay alguna advertencia?

Codeception puede ser empleado por desarrolladores con niveles de dominio de PHP muy diferentes y equipos de todos los tamaños.

Codeception puede ser empleado por desarrolladores con niveles de dominio de PHP muy diferentes y equipos de todos los tamaños.
Pío

En mi opinión, este marco de prueba es adecuado para todo tipo de equipos diferentes: grandes y pequeños, principiantes y profesionales de PHP experimentados, aquellos que usan un marco popular y aquellos que no usan ningún marco.

En cualquier caso, todo se reduce a esto: Codeception está listo para el horario de máxima audiencia.

Es un marco maduro y bien documentado que puede ampliarse fácilmente con numerosos módulos. Codeception es moderno, pero se basa en el PHPUnit probado en el tiempo, lo que debería tranquilizar a los desarrolladores que no quieren experimentar demasiado.

Funciona bien, lo que significa que es rápido y no requiere demasiado tiempo y esfuerzo. Mejor aún, es relativamente fácil de dominar y la abundante documentación debería ayudar a un proceso de aprendizaje sin complicaciones.

Codeception también es fácil de instalar y configurar, pero cuenta con muchas opciones avanzadas. Si bien la mayoría de los usuarios no necesitarán todos (o, de hecho, la mayoría), todo depende de lo que pretenda hacer con ellos. Puede comenzar con lo básico, y las funciones adicionales serán útiles tarde o temprano.

Relacionado: Código PHP con errores: los 10 errores más comunes que cometen los desarrolladores de PHP