How can I mock static method of class using mockery? - laravel

I have this class:
<?php
namespace App\Http\Controllers\Alerts;
use App\Http\Controllers\Controller;
use App\Models\Alert;
use App\Models\FiredAlert;
use App\Models\UnitReport;
use App\Notifications\AlertSetup;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Notification;
class AlertController extends Controller
{
/**
* #param Alert $alert
* #param null $schema
*/
public static function checkForInactivity(Alert $alert, $schema = null): void
{
...some code...
}
/**
* Get int day of the week
* #return int
*/
public static function getDayOfTheWeek(): int
{
return Carbon::now()->dayOfWeek;
}
/**
* Get all alerts available fot the current day and process it
*/
public static function checkForInactivityAlerts(): void
{
$alerts = Alert::where('day', self::getDayOfTheWeek())->get());
foreach ($alerts as $alert) {
self::checkForInactivity($alert);
}
}
}
I would like to mock getDayOfTheWeek and checkForInactivity and call checkForInactivityAlerts, something like:
$mockAlertController = Mockery::mock("alias:App\Http\Controllers\Alerts\AlertController");
$mockAlertController->shouldReceive('getDayOfTheWeek')->andReturn(2);
$mockAlertController->shouldReceive('checkForInactivity')->once();
AlertController::checkForInactivityAlerts()
But I got the error:
Mockery\Exception\BadMethodCallException : Static method
App\Http\Controllers\Alerts\AlertController::checkForInactivityAlerts()
does not exist on this mock object
How can I solve this?

Related

Getting undefined property error exception when changing mail::send to mail::queue in laravel 8

Here is code that works:
Mail::to($emails)->send(new ExceptionOccurred($e));
And then I change it to:
Mail::to($emails)->queue(new ExceptionOccurred($e));
When I do I get the error:
ErrorException: Undefined property: App\Mail\ExceptionOccurred::$content in C:\inetpub\wwwroot\laravel\app\Mail\ExceptionOccurred.php:33
This is ExceptionOccurred.php:
namespace App\Mail;
use Illuminate\Bus\Queueable;
// use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ExceptionOccurred extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($content)
{
$this->content = $content;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('mail.ExceptionOccurred')
->subject('Exception on live instance')
->with('content', $this->content);
}
}
This is the relevant portion of the exception handler:
if ( $exception instanceof Exception ) {
$e = FlattenException::create($exception);
} else {
$e = $exception;
}
$emails = json_decode( env('MAINTAINER_EMAILS') );
if (app()->environment('production') || app()->environment('testing') ) {
Mail::to($emails)->send(new ExceptionOccurred($e));
}
To re-iterate, Mail::send() works, but Mail::queue() does not. I believe the queue is set up correctly.
You have to define the content attribute before the construct, like this:
namespace App\Mail;
use Illuminate\Bus\Queueable;
// use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ExceptionOccurred extends Mailable
{
use Queueable, SerializesModels;
public $content;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($content)
{
$this->content = $content;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('mail.ExceptionOccurred')
->subject('Exception on live instance')
->with('content', $this->content);
}
}
Reference: https://laravel.com/docs/8.x/mail#view-data

Class App\Http\Requests\TestRequest does not exist? But I am using this class in Controller

I am using same App\Http\Requests\TestRequest in controller but its display message this Class not exit what can be problem? Plz help me?
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\TestRequest;
use App\Student;
class InsertController extends Controller
{
public function insert(TestRequest $request){
$obj = new Student();
$obj->Name =$request->name;
$obj->City = $request->city;
$obj->save();
return view('submit');
}
}
TestRequest Code is Here!
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class TestRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'Name'=>'required'
'City'=>'required'
];
}
}
Above Both codes are of Request folder And controller folder, I have done everything, i have done this class in Controller but its showing that not exist why? please Help me.

How to use the method setup from PHPUnit in Laravel 5.8

I used to use the method setup of PHPUnit to create a instance for my test methods. But in Laravel 5.8 I can't do it
I've tried both ways, and it's works makes an instance per method how showed below.
This works:
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Service\MyService;
class MyServiceTest extends TestCase
{
/**
* A basic unit test example.
*
* #return void
*/
public function testInstanceOf()
{
$myService = new MyService;
$this->assertInstanceOf( 'App\Service\MyService' , $myService );
}
}
This doesn't works:
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Service\MyService;
class MyServiceTest extends TestCase
{
private $instance;
function setUp(){
$this->instance = new MyService;
}
/**
* A basic unit test example.
*
* #return void
*/
public function testInstanceOf()
{
$myService = $this->instance;
$this->assertInstanceOf( 'App\Service\MyService' , $myService );
}
}
This error message below show in console:
PHP Fatal error: Declaration of Tests\Unit\MyServiceTest::setUp() must be compatible with Illuminate\Foundation\Testing\TestCase::setUp(): void in /home/myproject/tests/Unit/MyServiceTest.php on line 10
Laravel 5.8 added the void typehint to the return type of the setUp method.
So you have to declare that like this:
public function setUp(): void
{
// you should also call parent::setUp() to properly boot
// the Laravel application in your tests
$this->instance = new MyService;
}
Note the : void after the function arguments to state the return type of that function
This is what i did and it help
/**
* Set up the test
*/
public function setUp(): void
{
parent::setUp();
$this->faker = Faker::create();
}
/**
* Reset the migrations
*/
public function tearDown(): void
{
$this->artisan('migrate:reset');
parent::tearDown();
}
Not stating the return type to void in the functions

How can I create a controller constructor in Laravel that takes in two concrete implementations of the same interface?

Background
Note: this is using Laravel 5.3, Please don't judge.
We are trying to use dependency injection with our laravel controllers and push as much business logic into repos that are injected to controllers upon the controller instantiation.
We already have this functioning example:
class AcmeController extends Controller
{
protected $repository;
public function __construct(AcmeInterface $repository)
{
$this->repository = $repository;
}
}
inside app/Providers/RepositoryServiceProvider.php we do the binding:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Repositories\Contracts\AcmeInterface::class, \App\Repositories\OpCity\AcmeRepo::class);
}
}
and then the AcmeRepo naturally implements the AcmeInterface:
class AcmeRepo implements AcmeInterface
Question
right now we have a case where some of the data of the same model is persisted in a memory type storage (redis) and the rest is persisted in relational db storage (psql). We would like to have two separate repos where each repo is specific to its storage type, ie RedisAcmeRepo and SqlAcmeRepo
How is it possible to do this in the AcmeController constructor?
public function __construct(AcmeInterface $sqlRepo, AcmeInterface $redisRepo)
{
$this->sqlRepo = $sqlRepo;
$this->redisRepo = $redisRepo;
}
For example you may do this:
$this->app->bind(AcmeController::class, function ($app) {
return new AcmeController($app->make(sqlRepo::class), $app->make(redisRepo::class));
});
Or this:
$this->app->when(AcmeController::class)
->needs('$sqlRepo')
->give($app->make(sqlRepo::class));
$this->app->when(AcmeController::class)
->needs('$redisRepo')
->give($app->make(redisRepo::class));
based on the answers above I came up with this solution, that kind of uses the composite pattern as well (I changed the name of the repos from Acme to ShopperLogs):
<?php
interface ShopperLogInterface
{
public function getLogs($from, $to, $shopper);
}
class ShopperLogsController extends Controller
{
/**
* service
*
* #var \App\Repositories\Contracts\ShopperLogInterface
* #access protected
*/
protected $manager;
public function __construct(ShopperLogInterface $manager)
{
$this->manager = $manager;
}
}
class ShopperLogManager implements ShopperLogInterface
{
protected $sqlRepo;
protected $redisRepo;
public function __construct(ShopperLogInterface $sqlRepo, ShopperLogInterface $redisRepo)
{
$this->sqlRepo = $sqlRepo;
$this->redisRepo = $redisRepo;
}
public function getLogs($from, $to, $shopper)
{
$todayRange = //get the today part of from -- to
/**
* array of ShopperLogs
*/
$todaysLogs;
if ($todayRange) {
$this->redisRepo->getLogs($todayRange->start, $todayRange->finish, $shopper);
}
$legacyRange = //get the part of from -- to that excludes today's range
/**
* array of ShopperLogs
*/
$legacyLogs;
if ($legacyLogs) {
$this->sqlRepo->getLogs($todayRange->start, $todayRange->finish, $shopper);
}
return merge($todayRange, $legacyRange);
}
}
class ShopperLogsSqlRepo implements ShopperLogInterface
{
/**
* #var /Illuminate\Database\Eloquent\Model/ShopperLogs
*/
protected $model;
/**
* #param /Illuminate\Database\Eloquent\Model/ShopperLogs $model
*/
public function __construct(ShopperLogs $model)
{
$this->model = $model;
}
public function getLogs($from, $to, $shopper)
{
$this->model->whereLogs //do eloquent sql stuff here
}
}
class ShopperLogsRedisRepo implements ShopperLogInterface
{
/**
* #var \Redis\Model\Class
*/
protected $model;
/**
* #param \Redis\Model\Class $model
*/
public function __construct(ShopperLogs $model)
{
$this->model = $model;
}
public function getLogs($from, $to, $shopper)
{
$this->model->whereLogs //do redis stuff
}
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, \App\Managers\ShopperLogManager::class);
$this->app->bind(ShopperLogsController::class, function ($app) {
return new ShopperLogsController($app->make(ShopperLogManager::class));
});
$this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, function() {
return new \App\Managers\ShopperLogManager(new \App\Repositories\ShopperLogsSqlRepo(new \App\ShopperLog), new \App\Repositories\ShopperLogsRedisRepo(new \App\ShopperLog));
});
}
}

ReflectionException in CommanderTrait.php line 59: Class App\FollowUserCommand does not exist

I Was following Laracasts video for creating follow option but when I'm clicking on Follow button on members page it is showing the above error. This is my followcontroller
<?php
namespace App\Http\Controllers;
use App\User;
use Laracasts\Commander\CommanderTrait;
use App\FollowUserCommand;
use Sentinel;
use Illuminate\Support\Facades\Input;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class FollowsController extends Controller
{
use CommanderTrait;
/**
* Follow a User
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store()
{
$input = array_add(Input::all(), 'user_id', Sentinel::getuser()->id);
$this->execute(FollowUserCommand::class, $input);
return Redirect::back();
}
/**
* Unfollow a User
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
This is my FollowUserCommand
<?php namespace App\User;
class FollowUserCommand {
public $user_id;
public $userIdToFollow;
function __construct($user_id, $userIdToFollow)
{
$this->user_id = $user_id;
$this->userIdToFollow = $userIdToFollow;
}
}
FollowUserCommandHandler
<?php namespace App;
use Laracasts\Commander\CommandHandler;
class FollowUserCommandHandler implements CommandHandler {
protected $userRepo;
function __construct(UserRepository $userRepo)
{
$this->userRepo = $userRepo;
}
public function handle($command)
{
$user = $this->userRepo->findById($command->user_id);
$this->userRepo->follow($command->userIdToFollow, $user);
return $user;
}
}
UserRepository
class UserRepository {
public function save(User $user)
{
return $user->save();
}
public function getPaginated($howMany = 4)
{
return User::orderBy('first_name', 'asc')->paginate($howMany);
}
public function findByUsername($username)
{
return User::with(['feeds' => function($query)
{
$query->latest();
}
])->whereUsername($username)->first();
}
public function findById($id)
{
return User::findOrFail($id);
}
public function follow($userIdToFollow, User $user)
{
return $user->follows()->attach($userIdToFollow);
}
}
User.php
<?php namespace App;
use Cartalyst\Sentinel\Users\EloquentUser;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends EloquentUser {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes to be fillable from the model.
*
* A dirty hack to allow fields to be fillable by calling empty fillable array
*
* #var array
*/
protected $fillable = [];
protected $guarded = ['id'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
/**
* To allow soft deletes
*/
use SoftDeletes;
protected $dates = ['deleted_at'];
// This function allows us to get a list of users following us
public function follows()
{
return $this->belongsToMany(self::class, 'follows', 'follower_id', 'followed_id')->withTimestamps();
}
// Get all users we are following
public function following()
{
return $this->belongsToMany('User', 'followers', 'user_id', 'follow_id')->withTimestamps();
}
}
Can anyone tell me why it is showing error even after "use App\FollowUserCommand;" has been declared in namespace.
Your namespace when declaring the FollowUserCommand class is wrong, it should be:
<?php namespace App;
class FollowUserCommand {...
And right now you have <?php namespace App\User;.

Resources