pakistanigeek's avatar

IOC Container Bindings are not available in Unit Test

Hi, I have bound an Interface in IOC Container using Service provider, I found it working while resolving it using tinker but when I use it in unit test it doesn't find any binding. Could someone help me to resolve this issue. Thanks in advance.

Code in service provider.

    // Private chat
        $this->app->bind(IPrivateChat::class, function ($app){
            return $this->app->makeWith(IChatService::class, ['sid'=> $this->twilioPrivatechatServiceId]);
        });

Code in service class

    public function __construct()
    {
        $this->chatServiceClient = resolve(IPrivateChat::class);
    }

Code in unit test class

        $channel = (new CreateTwilioChannelService())->execute($data);

When i dd(app()->getBindings()) in tinker i get all of my bindings along with core framework, but when i dd(app()->getBindings()) i get an empty list.

Updated:

Complete code CreateTwilioChannelService.php

<?php 
namespace App\Services\Twilio;

use App\Contracts\IPrivateChat;

class CreateTwilioChannelService
{
    protected $chatServiceClient;

    public function __construct()
    {
        $this->chatServiceClient = resolve(IPrivateChat::class);
    }


    public function execute($data)
    {
        
    }
}

IPrivateChat.php

<?php 
namespace App\Contracts;

interface IPrivateChat{

}

IChatService.php

<?php
namespace  App\Contracts;

class IChatService{

    public function channels(){}

    public function users(){}
}

TwilioServiceProvider.php

<?php

namespace App\Providers;

use App\Contracts\IChatService;
use App\Contracts\IPrivateChat;
use Illuminate\Support\ServiceProvider;
use Twilio\Rest\Client;

class TwilioServiceProvider extends ServiceProvider
{
    protected $twilioAccountSid;
    protected $twilioAuthToken;
    protected $twilioApiKey;
    protected $twilioApiSecret;
    protected $twilioWatercoolerServiceId;
    protected $twilioPrivatechatServiceId;


    public function __construct($app)
    {
        $this->twilioAccountSid = config('twilio')['accountSid'];;
        $this->twilioAuthToken = config('twilio.authToken');
        $this->twilioApiKey = config('twilio')['apiKey'];
        $this->twilioApiSecret = config('twilio')['apiSecret'];
        $this->twilioWatercoolerServiceId = config('twilio.watercoolder.chatServiceSid');
        $this->twilioPrivatechatServiceId = config('twilio.privatechat.chatServiceSid');
        parent::__construct($app);
    }
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {

        // Twilio client binding
        $this->app->bind(Client::class, function($app){
            return  new Client($this->twilioAccountSid, $this->twilioAuthToken);
        });

        $this->app->bind(IChatService::class, function($app, $params){
            return $this->app->make(Client::class)->chat->v2->services($params['sid']);
        });

        // Private chat
        $this->app->bind(IPrivateChat::class, function ($app){
            return $this->app->makeWith(IChatService::class, ['sid'=> $this->twilioPrivatechatServiceId]);
        });

    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

CreateTwilioChannelServiceTest.php

<?php

namespace Tests\Unit\Services\Twilio;

use App\Contracts\IPrivateChat;
use App\Services\Twilio\CreateTwilioChannelService;
use PHPUnit\Framework\TestCase;

class CreateTwilioChannelServiceTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function testCreateTwilioChannel()
    {

        $data = [];

        // dd(app(IPrivateChat::class));
        $channel = (new CreateTwilioChannelService())->execute($data);
        
        // dd($channel);

    }
}
0 likes
8 replies
tykus's avatar

Whenever you new up a class; you are bypassing the Container (and your bindings). If you were to resolve the CreateTwilioChannelService class out of the container, then it should work. You should be able to typehint the chatServiceClient in the constructor also:

public function __construct(IPrivateChat $chatServiceClient)
{
    $this->chatServiceClient = $chatServiceClient;
}
$channel = resolve(CreateTwilioChannelService::class)->execute($data);
pakistanigeek's avatar

@tykus With this code, i am again getting the same error.

 $message = "Target [$concrete] is not instantiable.";
tykus's avatar

@pakistanigeek can you describe the hierarchy of IPrivateChat, IChatService and CreateTwilioChannelService , and show the implementation of CreateTwilioChannelService?

tykus's avatar

@pakistanigeek first thing I see is you are using the PHPUnit TestCase; so the Container is not available to you

use PHPUnit\Framework\TestCase;

Next IChatService is a class (in a Contracts namespace???) which does not implement IPrivateChat interface; is this correct?

pakistanigeek's avatar

@tykus lets get to simple, i am writing dd(app()->getBindings()); in unit test class and i am getting empty array.

tykus's avatar
tykus
Best Answer
Level 104

@pakistanigeek of course, because the application is not created because you are extending the PHPUnit TestCase rather than the Laravel Tests\TestCase class.

pakistanigeek's avatar

@tykus Thanks, I didn't check this out, yes its working now when i changed namespace from

use PHPUnit\Framework\TestCase;

to

use Tests\TestCase;

Please or to participate in this conversation.