Introducción

Al momento de probar aplicaciones de Laravel, puedes querer "simular" (mock) ciertos aspectos de tu aplicación de modo que realmente no sean ejecutados durante una prueba dada. Por ejemplo, al momento de probar un controlador que despacha un evento, puedes querer simular los listeners de eventos de modo que realmente no se ejecuten durante la prueba. Esto te permite probar solamente la respuesta HTTP del controlador sin preocuparte por la ejecución de los listeners de eventos, ya que los listeners de eventos pueden ser evaluados en sus propios casos de prueba.

Laravel provee funciones helpers para simular eventos, tareas y clases facades predeterminadas. Estos helpers proporcionan principalmente una capa conveniente sobre la clase Mockery de modo que no tengas que hacer manualmente llamadas complicadas a métodos Mockery. Puedes también usar Mockery o PHPUnit para crear tus propios mocks o spies.

Mocking de objetos

Cuando hagas mocking de un objeto que vas a inyectar en tu aplicación a través del contenedor de servicio de Laravel, debes enlazar tu instancia a la que le has hecho mocking al contenedor como un enlace de instance. Esto le indicará al contenedor que use tu instancia "mockeada" del objeto en lugar de construir el propio objeto:

use App\Service;
use Mockery;

$this->instance(Service::class, Mockery::mock(Service::class, function ($mock) {
    $mock->shouldReceive('process')->once();
}));

Para hacer esto más conveniente, puedes usar el método mock, que es proporcionado por la clase TestCase base de Laravel:

use App\Service;

$this->mock(Service::class, function ($mock) {
    $mock->shouldReceive('process')->once();
});

Puedes usar el método partialMock cuando sólo necesitas simular algunos métodos de un objeto. Los métodos que no son simulados serán ejecutados de forma normal al ser llamados:

use App\Service;

$this->partialMock(Service::class, function ($mock) {
    $mock->shouldReceive('process')->once();
});

De forma similar, si quieres espiar un objeto, la clase de prueba base de Laravel ofrece un método spy como un wrapper conveniente del método Mockery::spy:

use App\Service;

$this->spy(Service::class, function ($mock) {
    $mock->shouldHaveReceived('process');
});

Fake de trabajos (jobs)

Como una alternativa a mocking, puedes usar el método fake de la clase facade Bus para evitar que determinadas tareas sean despachadas. Al momento de usar fakes, las aserciones serán hechas después de que el código bajo prueba sea ejecutado.

<?php

namespace Tests\Feature;

use App\Jobs\ShipOrder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Bus;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function testOrderShipping()
    {
        Bus::fake();

        // Perform order shipping...

        Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) {
            return $job->order->id === $order->id;
        });

        // Assert a job was not dispatched...
        Bus::assertNotDispatched(AnotherJob::class);
    }
}

Fake de eventos

Como una alternativa a mocking, puedes usar el método fake de la clase facade Event para prevenir la ejecución de todos los listeners de eventos. Después puedes comprobar que los eventos fueron despachados e incluso inspeccionar los datos que recibieron. Al momento de usar fakes, las aserciones son hechas después de que el código bajo prueba sea ejecutado:

<?php

namespace Tests\Feature;

use App\Events\OrderFailedToShip;
use App\Events\OrderShipped;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
    * Test order shipping.
    */
    public function testOrderShipping()
    {
        Event::fake();

        // Perform order shipping...

        Event::assertDispatched(OrderShipped::class, function ($e) use ($order) {
            return $e->order->id === $order->id;
        });

        // Assert an event was dispatched twice...
        Event::assertDispatched(OrderShipped::class, 2);

        // Assert an event was not dispatched...
        Event::assertNotDispatched(OrderFailedToShip::class);
    }
}

Después de llamar a Event::fake(), no se ejecutarán listeners de eventos. Entonces, si tus pruebas usan model factories que dependen de eventos, como crear una UUID durante el evento de modelo creating, debes llamar Event::fake() después de usar tus factories.

Haciendo fake a un subconjunto de eventos

Si sólo deseas hacer fake a listeners de eventos para un grupo específico de eventos, puedes pasarlos a los métodos fake o fakeFor:

/**
* Test order process.
*/
public function testOrderProcess()
{
    Event::fake([
        OrderCreated::class,
    ]);

    $order = factory(Order::class)->create();

    Event::assertDispatched(OrderCreated::class);

    // Other events are dispatched as normal...
    $order->update([...]);
}

Regístrate en Styde

Para obtener acceso a ésta y a todas nuestras lecciones y cursos premium:

Ver planes

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Pruebas de Base de Datos - Documentación de Laravel 6 Lección siguiente Laravel Cashier - Documentación de Laravel 6