es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

phpunit no elimina los registros creados por factory después del bloque catch.

Estoy escribiendo pruebas en el framework Laravel con PHPUnit Versión 9.0 (Versión de PHP 7.4). Utilizo factories para crear registros de base de datos para cada prueba.

Tengo que probar el método failed de un Job, que lanza una excepción al final. El código de este método se ve así (no puedo mostrar el código real):

public function failed(\Exception $exception)
{
    Patient::find($this->user->id)->update([
        'export_status_type' => 'failed',
        'ended_at' => date('Y-m-d H:i:s')
    ]);

    \Storage::put('protocols/exports/' . $this->path, $content);

    throw new ExportException('Export failed');
}

En mi prueba, vinculo la llamada al método en un bloque try and catch. De lo contrario, se detendrá después de llamar al método debido a la excepción lanzada.

El problema es que no elimina los registros de la base de datos que las pruebas crean a través de factories. Aquí está el código de mi prueba:

use WithoutMiddleware;
use DatabaseTransactions;

/** @test */
public function it_fails_to_export()
{
    // Crea registros de base de datos a través de database factories
    $partner = $this->createPartners();
    $this->createPatients($partner);
    $this->createProtocols($partner);

    // Realiza pruebas para los registros creados
    $this->assertCount(3, Patient::all());
    // ...

    try
    {
        $export_job = new ExportJob;
        // llama a la función failed que actualiza un registro de base de datos y lanza una excepción
        $export_job->failed(new ExportException('failed'));
    }
    catch (ExportException $exception)
    {
        // El mensaje anterior siempre llega al bloque catch debido a la excepción lanzada. Aquí se deben realizar algunas afirmaciones
        $this->assertCount(3, Patient::all());

        // Después de las pruebas, debo eliminar forzadamente todas las tablas de base de datos utilizadas, porque phpunit no las elimina automáticamente en ese caso.
        Patient::withTrashed()->forceDelete();
        Partner::withTrashed()->forceDelete();
        Protocol::withTrashed()->forceDelete();
    }
}

¿Hay alguna otra forma de decirle a phpunit/laravel que ignore la excepción lanzada en este caso? No necesito esto para cada prueba, pero especialmente para esa. Porque con el bloque try and catch, phpunit no elimina los registros de base de datos creados (a través de factories).

¿O falta algo más/está mal?

Espero que alguien tenga una idea 🙂

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Una forma de resolver este problema es usar la anotación @expectedException de PHPUnit para indicar que este método de prueba espera que se lance una determinada excepción. Luego, PHPUnit capturará la excepción esperada y seguirá ejecutando el método de prueba, incluyendo la eliminación de los registros de base de datos creados por las factorías.

    Así es como puedes modificar el método de prueba para usar @expectedException:

    /** 
     * @test 
     * @expectedException \ExportException 
     */
    public function it_fails_to_export()
    {
        // crear registros de base de datos a través de las factorías
    
        $export_job = new ExportJob;
    
        // llamar a la función fallida que actualiza un registro de base de datos y lanza una excepción
        $export_job->failed(new ExportException('fallo'));
    
        // realizar afirmaciones sobre los registros de base de datos creados
        $this->assertCount(3, Patient::all());
    
        // los registros de base de datos creados por las factorías se eliminarán automáticamente por PHPUnit
    }
    

    Con esta modificación, el método de prueba pasará siempre y cuando se lance una ExportException por el método failed. PHPUnit capturará la excepción y la ignorará, luego continuará ejecutando el método de prueba, incluyendo la eliminación de los registros de base de datos creados por las factorías.

    Nota: si necesitas hacer aserciones adicionales sobre el objeto Exception en sí, puedes usar la anotación @expectedExceptionMessage para verificar el mensaje de error y @expectedExceptionCode para verificar el código de error.

    ¡Espero que esto te ayude!

Comments are closed.