PHPUnit test for Laravel Artisan command without calling external API in inner instance (dependency injection) - laravel

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

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

Related

Laravel IOC not calling the constructor

I have binding in the service provider
$this->app->singleton(
'App\Models\Subscription\Interfaces\IInvoiceService',
'App\Models\Subscription\Impl\InvoiceService'
);
class InvoiceService implements IInvoiceService
{
protected $repo;
public function _construct(){
$this->app = App::getFacadeRoot();
$this->repo = $this->app['repo'];
}
public function Create()
{
}
}
In one of the classes in Injected the IInovoice Service.
I am getting the concrete implementation of IInovoice . but the Constructor of the InvoiceService is never getting called
Try the following
class InvoiceService implements IInvoiceService
{
protected $app;
protected $repo;
public function _construct($app, $repo) {
$this->app = $app;
$this->repo = $repo;
}
public function Create() {
}
}
App\Providers\AppServiceProvider
public function register() {
$this->app->singleton(
'App\Models\Subscription\Interfaces\IInvoiceService',
'App\Models\Subscription\Impl\InvoiceService'
);
$this->app->when('App\Models\Subscription\Impl\InvoiceService')
->needs('$app')
->give($this->app->getFacadeRoot());
$this->app->when('App\Models\Subscription\Impl\InvoiceService')
->needs('$repo')
->give($this->app['repo']);
}
public function boot(ResponseFactory $response) {
//uncomment this line to debug InvoiceService Resolving event
//$this->app->resolving(App\Models\Subscription\Impl\InvoiceService::class, function ($invoiceService, $app) {
//dump('resolves InvoiceService', $invoiceService);
//});
}
Then run
php artisan clear-compiled
php artisan config:clear

How can I solve Target [App\Repositories\NewsRepository] is not instantiable while building [App\Http\Controllers\Member\NewsController].?

My controller like this :
...
use App\Repositories\NewsRepository;
class NewsController extends Controller
{
protected $repository;
public function __construct(NewsRepository $repository)
{
$this->repository = $repository;
}
public function store(NewsCreateRequest $request)
{
...
$news = $this->repository->create($input);
...
}
}
My interface like this :
namespace App\Repositories;
use Prettus\Repository\Contracts\RepositoryInterface;
interface NewsRepository extends RepositoryInterface
{
//
}
My class like this :
...
use App\Repositories\NewsRepository;
class NewsRepositoryEloquent extends BaseRepository implements NewsRepository
{
public function model()
{
return News::class;
}
public function boot()
{
$this->pushCriteria(app(RequestCriteria::class));
}
}
My repository service provider like this :
...
class RepositoryServiceProvider extends ServiceProvider
{
...
public function register()
{
...
$this->app->bind(\App\Repositories\NewsRepository::class, \App\Repositories\NewsRepositoryEloquent::class);
}
}
If the method store on the controller executed, there exist error :
(1/1) BindingResolutionException Target
[App\Repositories\NewsRepository] is not instantiable while building
[App\Http\Controllers\Member\NewsRepository].
How can I solve the error?
You have to add constructor to your repository and call parent constructor for setup model like this:
public function __construct(Permission $model)
{
parent::__construct($model);
}

Model Event not working

I have the following model:
class ProjectTwitterStatus extends Eloquent {
protected $table = 'project_twitter_statuses';
protected $softDelete = true;
protected $guarded = array('id');
public static function boot()
{
parent::boot();
ProjectTwitterStatus::deleting(function($projectTwitterStatus)
{
$projectTwitterStatus->deleted_by = Auth::user()->id;
});
}
public function twitterStatus() {
return $this->belongsTo('TwitterStatus');
}
public function twitterRetweet() {
return $this->belongsTo('TwitterRetweet','twitter_status_id','twitter_status_id');
}
public function project() {
return $this->belongsTo('Project');
}
}
Somewhere in my app an item is deleted using one of the following statements:
ProjectTwitterStatus::find($id)->delete();
ProjectTwitterStatus::whereIn('twitter_status_id', $twitterStatusIds)->delete();
I can see in the database the item had been (soft) deleted. But the deleted_by column is not filled.
Does anyone know what I am doing wrong?
Try using Late Static Binding, like following-
class ProjectTwitterStatus extends Eloquent {
public static function boot ()
{
parent::boot();
static::deleting(function($projectTwitterStatus)
{
$projectTwitterStatus->deleted_by = Auth::user()->id;
});
}
}

How add a specific variable in custom AuthStorage in Zend Framework 2

I'm working on ZF2 and I have developped my own storage for authentication but I wonder how to add a new persistent variable (session-like).
Look My Auth Storage :
<?php
namespace Application\Model;
use Zend\Authentication\Storage;
use Zend\Authentication\Storage\StorageInterface;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use Application\Model\User;
class MyAuthStorage implements Storage\StorageInterface, ServiceManagerAwareInterface
{
protected $storage;
protected $userTable;
protected $resolvedIdentity;
protected $serviceManager;
public function isEmpty() {
[...]
}
public function read() {
[...]
}
public function write($contents) {
[...]
}
public function clear() {
[...]
}
public function getStorage() {
[...]
}
public function setStorage(Storage\StorageInterface $storage) {
[...]
}
public function getUserTable() {
[...]
}
public function getServiceManager() {
[...]
}
public function setServiceManager(ServiceManager $serviceManager) {
[...]
}
}
I would like to add a variable called foo in my storage (my session ?)
I try this, but it doesn't work :
protected $foo;
public function setFoo($value) {
$this->foo= $value;
}
public function getFoo() {
return $this->foo;
}
Any ideas ?
Ok, I found something and it works for me :
I've added these things in my auth storage class
use Zend\Session\Container;
Then,
protected $container;
public function setContainer(Container $container) {
$this->container = $container;
return $this->container;
}
public function getContainer() {
if (!isset($this->container)) {
$this->setContainer(new Container('myauthstorage'));
}
return $this->container;
}
And now I can do in my controller stuff like that :
$container = $this->getServiceLocator()->get('AuthService')->getStorage()->getContainer();
$container->foo = true;
if ($container->foo) {
// Congrats !
}
A good example how to write last login time.
namespace Application\Model;
use Zend\Authentication\Storage;
class AuthStorage extends Storage\Session
{
public function setRememberMe($rememberMe = 0, $time = 1209600)
{
if ($rememberMe == 1) {
$this->session->getManager()->rememberMe($time);
}
}
public function forgetMe()
{
$this->session->getManager()->forgetMe();
}
public function lastLogin()
{
$this->session->{$this->getMember()}->last_login = time();
}
}
Check this tutorial :
http://samsonasik.wordpress.com/2012/10/23/zend-framework-2-create-login-authentication-using-authenticationservice-with-rememberme/
Sounds like your personnal AuthStorage should extends Storage\Session like this :
namespace SanAuth\Model;
use Zend\Authentication\Storage;
class MyAuthStorage extends Storage\Session
{
public function setRememberMe($rememberMe = 0, $time = 1209600)
{
if ($rememberMe == 1) {
$this->session->getManager()->rememberMe($time);
}
}
public function forgetMe()
{
$this->session->getManager()->forgetMe();
}
}

CodeIgniter - Call method inside a model?

I have the following code:
class Badge extends CI_Model
{
public function foo()
{
echo $this->bar('world');
}
public function bar($word)
{
return $word;
}
}
But it always gives me an error on the line where echo $this->bar('world'); is.
Call to undefined method (......)
Your not loading your model inside your controller:
public function test()
{
$this->load->model('badge');
$this->badge->foo();
}
Because the code works - I've just tested it by pasting using your model unedited:
class Badge extends CI_Model
{
public function foo()
{
echo $this->bar('world');
}
public function bar($word)
{
return $word;
}
}
output:
world
In order to avoid any external call dependecy you need to get the Codeigniter instance and call the method through the instance.
class Badge extends CI_Model
{
public function foo()
{
$CI =& get_instance();
echo $CI->Badge->bar('world');
}
public function bar($word)
{
return $word;
}
}

Resources