21
votes

I'm trying to write a test class for a shopping cart. Here is what I have:

ShoppingCartTest.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);
    }

}

However, when I run phpunit, it seems like Laravel is unable to resolve my ShoppingCartClass.

Here is the 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

I have my ShoppingCart class being resolved in a number of different controllers just fine.

Why can't Laravel resolve it during my tests?

I refered to this post as well but still didn't have any luck.

2
Could you post the constructor for App\Classes\Billing\ShoppingCart please? - edcs
@edcs Sure thing. Here is the class. pastebin.com/bPRpmtnH - Denis Priebe
Cool - thanks! You could try using $this->app->make('App\Classes\Billing\ShoppingCart'); as all Laravel tests have an instance of the application available to them as a property. - edcs
@edcs Thanks for the response. I tried with $this->app->make('App\Classes\Billing\ShoppingCart') and am now getting a new error. Fatal error: Call to a member function make() on null - Denis Priebe
Just looking at one of my own projects, I never use __construct() to create instances of things. Try renaming __construct() to setupShoppingCart() (or similar - the name doesn't matter) and create a docblock which has @before in it, like this: /** * @before */ - edcs

2 Answers

44
votes

I figured it out. Here is the updated class.

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);
    }

}

Thanks to @edcs for guiding me in the right direction. You need to use a setUp function and not __construct as the app instance hasn't been created yet.

0
votes

If you want to use __construct you have to use the same constructor of PHPUnit\Framework\TestCase and remember to call the parent method if you don't want to break anything

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

        // my init code
    }
}

However the proper way would be to use the method setUpBeforeClass() if you want to execute your init code once or setUp() if you want to execute the init code before each test contained in your class. Check PHPUnit documentation for more details.