DEV Community

Fran Iglesias
Fran Iglesias

Posted on • Originally published at franiglesias.github.io on

No hagas estos tests

O al menos, no de esta manera.

Objetos mensaje

Eventos, Comandos y Queries, son objetos que nos interesan por su significado y que llevan datos para sus respectivos handlers. En ocasiones me han planteado: ¿no hay que testear esto?

Quiero decir:

class PostWasCreated
{
    private string $title;
    private string $body;

    public function __construct(string $title, string $body)
    {
        $this->title = $title;
        $this->body = $body;
    }

    public function title(): string
    {
        return $this->title;
    }

    public function body(): string
    {
        return $this->body;
    }
}

Enter fullscreen mode Exit fullscreen mode

– ¿No hay que testear que se construye bien?

class PostWasCreatedTest extends TestCase
{
    public function testShouldCreateEvent(): void
    {
        $event = new PostWasCreated('Title', 'Body');

        self::assertTrue('Title', $event->title());
        self::assertTrue('Body', $event->body());
    }
}

Enter fullscreen mode Exit fullscreen mode

– Pues no. Tanto si es en una situación de TDD, como si en QA, este test es una pérdida de tiempo.

– Pero imagínate que te lías y asignas el valor de body a title y viceversa.

– Es que no lo tienes que testear así.

En primer lugar, buscamos testear comportamientos. Asignar los parámetros pasados a las propiedades no es un comportamiento en sí mismo.

– ¿Pero no testeas que se crean objetos consistentes? Si hasta tienes una kata basada en eso en este mismo blog.

– Por supuesto, pero lo que verificamos es que construimos objetos que cumplen reglas de negocio y mantienen invariantes. De nuevo: la inicialización de propiedades no es un comportamiento.

– ¿Entonces?

– La forma adecuada de testear esto es testeando su handler.

Imaginemos algún servicio de reservas que notifica a la usuaria por correo electrónico que la reserva ha sido realizada correctamente. Esto se hace porque al realizar la reserva, se lanza un evento BookingWasCreated, que contiene los datos básicos de la misma.

Uno de los suscriptores o listeners de este evento es SendConfirmationMessage que compone un mensaje y lo envía a través de un Mailer, aquí representado con un doble.

El razonamiento es el siguiente: si el evento está bien construido, el mensaje se construirá como se espera. Si el test falla porque el mensaje resultante es, por ejemplo, “Booked from 15/5/2021 to 15:35 @ 16:20”, está claro que en alguna parte se han cruzado los datos.

class SendConfirmationMessageTest extends TestCase
{
    public function testShouldNotify(): void
    {
        $event = new BookingWasCreated(
            'fran@example.com', 
            '15/5/2021', 
            '15:35', 
            '16:20'
        );

        $message = new Message('Booked from 15:35 to 16:20 @ 15/5/2021');
        $message->to('fran@example.com');

        $mailer = $this->createMock(Mailer::class);
        $mailer
            ->expect(self::once())
            ->method('send')
            ->with($message);

        $sendConfirmationMessage = new SendConfirmationMessage($mailer);

        $sendConfirmationMessage->handle($event);  
    }
}

Enter fullscreen mode Exit fullscreen mode

Todo esto aplica igualmente a DTO y otros objetos parámetros que solo llevan datos y no tienen comportamientos.

Top comments (0)