0
votes

I am trying to write a phpunit test with laravel 5.2 for a console command. Few resources seems promising, but so far I failed making it work. I am trying to follow info given here:

stackoverflow - PHPUnit test for Laravel Artisan command that calls an external API without calling that API physically?

Laravel binding

The test is calling a command that 'binds' ExternalAPI class in its constructor. In the test, I mock the ExternalAPI.

The ExternalAPI class:

Class ExternalAPI {
    protected $lang;

    public function __construct($lang)
    {
        $this->lang = $lang;
    }

    public function call_api($myparam){
        //do the api stuff here
    }

}

The command:

class MyCommand extends Command
{
    protected $signature = 'check:mycommand'; 
    protected $externalAPI ;

    public function __construct(ExternalAPI $externalAPI)
    {
        $this->externalAPI = $externalAPI;

        parent::__construct();
    }

    public function handle()
    {
        $res = $this->externalAPI->call_api('test');
    }

}

The test:

class MyCommandTest extends TestCase
{

    public function setUp()
    {
        parent::setUp();

        $methods_to_stub = ['call_api'];
        $mock = $this->getMockBuilder('\ExternalAPI')
            ->setConstructorArgs(array('param_value'))
            ->setMethods($methods_to_stub)
            ->getMock();
        $mock->method('call_api')->willReturn(44.44);
        $this->app->instance(ExternalAPI::class, $mock);    
    }

    public function test1()
    {
        $output = new BufferedOutput;
        Artisan::call('check:mycommand', [],$output);
        echo "output:$output\n\n";
    }

}

The error is:

Illuminate\Contracts\Container\BindingResolutionException: Unresolvable dependency resolving [Parameter #0 [ $myparam]] in class App\MyLibrary\ExternalAPI

1

1 Answers

0
votes

I managed to get it to work using mockery This is the corrected code that works for me:

The ExternalAPI class (I removed the param from the constructor because right now I didn't check if and how it can be done):

Class ExternalAPI {
    protected $lang;

    public function __construct()
    {
    }

    public function init($lang)
    {
        $this->lang = $lang;
    }


    public function call_api($myparam){
        //do the api stuff here
    }

}

The command:

class MyCommand extends Command
{
    protected $signature = 'check:mycommand'; 
    protected $externalAPI ;

    public function __construct()
    {
        $this->externalAPI = app(ExternalAPI::class);

        parent::__construct();
    }

    public function handle()
    {
        $this->externalAPI->init('whatever')
        $res = $this->externalAPI->call_api('test');
    }

}

The AppServiceProvider:

class AppServiceProvider extends ServiceProvider{
    public function boot()
    {
        $this->app->bind('App\MyLibrary\ExternalAPI',function(){
            return new \App\MyLibrary\ExternalAPI();
        });
    }
}

The test:

class MyCommandTest extends TestCase
{

    public function setUp()
    {
        parent::setUp();

        $mock = Mockery::mock('ExternalAPI');
        $mock->shouldReceive('call_api')->with(Mockery::any())->andReturn(44.44);
        $mock->shouldReceive('init')->with(Mockery::any());

        $this->app->instance(ExternalAPI::class, $mock);    
    }

    public function test1()
    {
        $output = new BufferedOutput;
        Artisan::call('check:mycommand', [],$output);
        echo "output:$output\n\n";
    }

}