Inyección de dependencia de pruebas unitarias de Laravel

3 minutos de lectura

Avatar de usuario de Denis Priebe
denis priebe

Estoy tratando de escribir una clase de prueba para un carrito de compras. Esto es lo que tengo:

PruebaCarrito.php

class ShoppingCartTest extends TestCase {

    use DatabaseTransactions;

    protected $shoppingCart;

    public function __construct() {
        $this->shoppingCart = resolve('App\Classes\Billing\ShoppingCart');
    }

    /** @test */
    public function a_product_can_be_added_to_and_retrieved_from_the_shopping_cart() {

        // just a placeholder at the moment
        $this->assertTrue(true);
    }

}

Sin embargo, cuando ejecuto phpunit, parece que Laravel no puede resolver mi ShoppingCartClass.

Aquí está el error:

Fatal error: Uncaught exception 'Illuminate\Contracts\Container\BindingResolutionException'
with message 'Unresolvable dependency resolving
[Parameter #0 [ <required> $app ]] in class Illuminate\Support\Manager'
in C:\Development Server\EasyPHP-Devserver-16.1\eds-www\nrponline\vendor\laravel\framework\src\Illuminate\Container\Container.php:850

Tengo mi clase ShoppingCart resuelta en varios controladores diferentes muy bien.

¿Por qué Laravel no puede resolverlo durante mis pruebas?

También me referí a esta publicación, pero todavía no tuve suerte.

  • ¿Podría publicar el constructor para App\Classes\Billing\ShoppingCart ¿por favor?

    – edcs

    17 de noviembre de 2016 a las 16:39

  • @edcs Claro. Aquí está la clase. pastebin.com/bPRpmtnH

    – Denis Priebe

    17 de noviembre de 2016 a las 16:44

  • ¡Genial, gracias! Podrías intentar usar $this->app->make('App\Classes\Billing\ShoppingCart'); ya que todas las pruebas de Laravel tienen una instancia de la aplicación disponible como propiedad.

    – edcs

    17 de noviembre de 2016 a las 16:54

  • @edcs Gracias por la respuesta. probé con $this->app->make('App\Classes\Billing\ShoppingCart') y ahora estoy recibiendo un nuevo error. Error fatal: llamada a una función miembro make () en nulo

    – Denis Priebe

    17 de noviembre de 2016 a las 17:07


  • Solo mirando uno de mis propios proyectos, nunca uso __construct() para crear instancias de cosas. Intenta cambiar el nombre __construct() a setupShoppingCart() (o similar – el nombre no importa) y crea un docblock que tiene @before en él, así: /** * @before */

    – edcs

    17 de noviembre de 2016 a las 17:12

Avatar de usuario de Denis Priebe
denis priebe

Me lo imaginé. Aquí está la clase actualizada.

class ShoppingCartTest extends TestCase {

    use DatabaseTransactions;

    protected $shoppingCart;

    public function setUp() {

        parent::setUp();

        $this->shoppingCart = $this->app->make('App\Classes\Billing\ShoppingCart');
    }

    /** @test */
    public function a_product_can_be_added_to_and_retrieved_from_the_shopping_cart() {

        // just a placeholder at the moment
        $this->assertTrue(true);
    }

}

Gracias a @edcs por guiarme en la dirección correcta. Necesita utilizar una función de configuración y no __construct como el app aún no se ha creado la instancia.

  • Deberías usar setUpBeforeClass() si desea ejecutar el código solo una vez como __construct() usualmente lo hace

    – Andrea Mauro

    10 de julio de 2019 a las 10:48

Si quieres usar __construct tienes que usar el mismo constructor de PHPUnit\Framework\TestCase y recuerda llamar al método padre si no quieres romper nada

class MyTest extends TestCase
{
    public function __construct($name = null, array $data = [], $dataName="")
    {
        parent::__construct($name, $data, $dataName);

        // my init code
    }
}

Sin embargo, la forma correcta sería usar el método setUpBeforeClass() si desea ejecutar su código de inicio una vez o setUp() si desea ejecutar el código de inicio antes de cada prueba contenida en su clase. Controlar Documentación de PHPUnit para más detalles.

  • inicialmente tuve __construct(...$args) { parent::__construct(...$args); ... } y falló en las pruebas con proveedores de datos. Esto funcionó.

    – s3c

    6 oct a las 21:26

¿Ha sido útil esta solución?