Buy Access to Course
23.

Probando con el transporte "en memoria

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Hace unos minutos, sólo en el entorno dev, hemos anulado todos nuestros transportes para que todos los mensajes se manejen de forma sincrónica. Por ahora lo hemos comentado, pero esto es algo que también podrías hacer en tu entorno test, para que cuando ejecutes las pruebas, los mensajes se manejen dentro de la prueba.

Esto puede ser o no lo que quieres. Por un lado, significa que tu prueba funcional está probando más. Por otro lado, una prueba funcional probablemente debería probar que la ruta funciona y que el mensaje se envía al transporte, pero la prueba del propio manejador debería hacerse en una prueba específica para esa clase.

Eso es lo que vamos a hacer ahora: encontrar una forma de no ejecutar los manejadores de forma sincrónica, pero probar que el mensaje se ha enviado al transporte. Por supuesto, si matamos al trabajador, podemos consultar la tabla messenger_messages, pero eso es un poco complicado y sólo funciona si utilizas el transporte Doctrine. Afortunadamente, hay una opción más interesante.

Empieza copiando config/packages/dev/messenger.yaml y pegándolo enconfig/packages/test/. Esto nos da una configuración de Messenger que sólo se utilizará en el entorno test. Descomenta el código y sustituye sync porin-memory. Hazlo para los dos transportes.

framework:
messenger:
transports:
async: 'in-memory://'
async_priority_high: 'in-memory://'

El transporte in-memory es realmente genial. De hecho, ¡vamos a verlo! Voy a pulsarShift+Shift en PhpStorm y buscaré InMemoryTransport para encontrarlo.

Esto... es básicamente un transporte falso. Cuando se le envía un mensaje, no lo maneja ni lo envía a ningún sitio, lo almacena en una propiedad. Si utilizaras esto en un proyecto real, los mensajes desaparecerían al final de la petición.

Pero, esto es súper útil para hacer pruebas. Vamos a probarlo. Hace un segundo, cada vez que ejecutamos nuestra prueba, nuestro trabajador empezó a procesar esos mensajes... lo cual tiene sentido: realmente los estábamos entregando al transporte. Ahora, borraré la pantalla y luego ejecutaré:

php bin/phpunit

Sigue funcionando... pero ahora el trabajador no hace nada: el mensaje ya no se envía realmente al transporte y se pierde al final de nuestras pruebas. Pero, desde la prueba, ahora podemos recuperar ese transporte y preguntarle cuántos mensajes se le han enviado

Obtener el servicio de transporte

Entre bastidores, cada transporte es en realidad un servicio del contenedor. Busca tu terminal abierto y ejecuta:

php bin/console debug:container async

Ahí están: messenger.transport.async ymessenger.transport.async_priority_high. Copia el segundo id de servicio.

Queremos verificar que el mensaje AddPonkaToImage se envía al transporte, y sabemos que se dirige a async_priority_high.

De vuelta a la prueba, esto es superguay: podemos obtener el objeto de transporte exacto que se acaba de utilizar desde dentro de la prueba diciendo:$transport = self::$container->get() y pegando luego el id de serviciomessenger.transport.async_priority_high

// ... lines 1 - 8
class ImagePostControllerTest extends WebTestCase
{
public function testCreate()
{
// ... lines 13 - 25
$transport = self::$container->get('messenger.transport.async_priority_high');
// ... line 27
}
}

Esta propiedad self::$container contiene el contenedor que se utilizó realmente durante la petición de la prueba y está diseñada para que podamos obtener lo que queramos de él.

Veamos qué aspecto tiene esto: dd($transport).

// ... lines 1 - 8
class ImagePostControllerTest extends WebTestCase
{
public function testCreate()
{
// ... lines 13 - 25
$transport = self::$container->get('messenger.transport.async_priority_high');
dd($transport);
}
}

Ahora vuelve a tu terminal y ejecuta:

php bin/phpunit

¡Bien! Esto vuelca el objeto InMemoryTransport y... ¡la propiedad sent contiene efectivamente nuestro objeto de mensaje! Todo lo que tenemos que hacer ahora es añadir una aserción para esto.

De vuelta a la prueba, voy a ayudar a mi editor añadiendo algunos documentos en línea para anunciar que esto es un InMemoryTransport. A continuación, añade $this->assertCount() para afirmar que esperamos que se devuelva un mensaje cuando digamos $transport->... veamos... el método al que puedes llamar en un transporte para obtener los mensajes enviados, o "en cola", es get().

// ... lines 1 - 6
use Symfony\Component\Messenger\Transport\InMemoryTransport;
class ImagePostControllerTest extends WebTestCase
{
public function testCreate()
{
// ... lines 13 - 24
/** @var InMemoryTransport $transport */
$transport = self::$container->get('messenger.transport.async_priority_high');
$this->assertCount(1, $transport->get());
}
}

¡Vamos a probarlo! Ejecuta:

php bin/phpunit

¡Lo tengo! Ahora estamos garantizando que el mensaje se ha enviado, pero hemos mantenido nuestras pruebas más rápidas y dirigidas al no intentar manejarlas de forma sincrónica. Si utilizáramos algo como RabbitMQ, tampoco necesitaríamos tenerlo en marcha cada vez que ejecutamos nuestras pruebas.

A continuación, ¡hablemos del despliegue! ¿Cómo ejecutamos nuestros trabajadores en producción... y nos aseguramos de que siguen funcionando?