How to use the method setup from PHPUnit in Laravel 5.8 - laravel

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

Related

Laravel problem passing variables from controller to mailer

I am having trouble passing variables from the controller to the mail fucntion I have tried to search it up on google but didn't find anything that works my goal is to get the variable from the form to the welcomemail.blade the current issue is that the variable doesnt get to my wlcomemail.php from the controller. the mailing part itself does work.
Controller code:
$email_data = array(
'first_name'=>'John',
'last_name'=>'Doe',
'email'=>'john#doe.com',
'password'=>'temp',
);
//Customer::create($data);
Mail::to($email_data['email'])->send(new welcomemail($email_data));
welcomemail.php code:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class welcomemail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $email_data;
public $example;
public function __construct()
{
$this->email_data = $email_data;
$this->example = 'example';
}
public function build()
{
return $this->markdown('emails.welcomemail');
}
}
blade code:
# Introduction
Welcome.
{{$email_data['first_name']}}
{{$example}}
#endcomponent
change this:
public function __construct()
{
$this->email_data = $email_data;
$this->example = 'example';
}
to:
public function __construct($email_data)
{
$this->email_data = $email_data;
$this->example = 'example';
}
now you have it in your mail class
it should work

How can I mock static method of class using mockery?

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?

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

How to test job arguments in Laravel?

How to test job arguments if Exception is thrown after job is dispatched. This test below returns green, but i found no way to test job arguments.
Code:
<?php
namespace Tests\Feature;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Tests\TestCase;
class SomeJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle() {}
}
class NothingTest extends TestCase
{
/** #test */
public function dispatch_test()
{
$this->expectException(\Exception::class);
$this->expectsJobs(SomeJob::class);
// job dispatched and Exception thrown afterwards
dispatch(new SomeJob("argument to test"));
throw new \Exception();
}
}
I actually ran into this earlier today myself. What I did to solve this issue was by using the withoutJobs() method instead. (Internally expectsJobs() calls this as well.) You can then assert against the dispatchedJobs property.
Because you are also 'expecting' and exception in your test you should wrap this in a callback and register it in a beforeApplicationDestroyed()
class SomeJob {
private $argument;
public function __construct($argument)
{
$this->argument = $argument;
}
}
class NothingTest extends TestCase
{
/** #test */
public function dispatch_test()
{
$this->expectException(\Exception::class);
$this->beforeApplicationDestroyed(function () {
// This part depends on how you would like to design this. You could
// use public properties, add a getter method on your job or use
// something like reflection to compare the properties.
$dispatchedJob = $this->dispatchedJobs[0];
$this->assertEquals(
'argument to test',
$this->getValue($dispatchedJob, 'argument')
);
});
// job dispatched and Exception thrown afterwards
dispatch(new SomeJob("argument to test"));
throw new \Exception();
}
protected function getValue($object, $name)
{
$ro = new \ReflectionObject($object);
$property = $ro->getProperty($name);
$property->setAccessible(true);
return $property->getValue($object);
}
}
ok. can test like this code below.
test looks nice, but you must use public properties and assign all arguments to the properties.
<?php
namespace Tests\Examples;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Tests\TestCase;
class SomeJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $arg1;
public $arg2;
public function __construct($arg1, $arg2)
{
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
public function handle() {}
}
class JobTest extends TestCase
{
/** #test */
public function dispatch_test()
{
$this->expectException(\Exception::class);
$this->expectsJobs(SomeJob::class);
$this->testJobInstance(SomeJob::class, function($job){
$this->assertEquals('arg1', $job->arg1);
$this->assertEquals('arg2', $job->arg2);
});
// job dispatched and Exception thrown afterwards
dispatch(new SomeJob("arg1", "arg2"));
throw new \Exception();
}
// will be pushed up to TestCase
protected function testJobInstance($class, callable $callback)
{
$this->beforeApplicationDestroyed(function () use($class, $callback) {
$job = collect($this->dispatchedJobs)->filter(function($job) use($class) {
return get_class($job) == $class;
})->first();
$callback($job);
});
}
}
Ok, the better way found...
I've made a helper function to dispatch jobs from IOC - it makes a lot easier to test jobs.
/**
* #param string | object $job
* #param array | null $args - associative array of arguments ['agr1' => 'value', 'arg2' => 2]
* #return mixed
*/
function dispatch_from_ioc($job, ? array $args)
{
if (is_string($job)) {
$job = app()->makeWith($job, $args);
}
return app(Dispatcher::class)->dispatch($job);
}
so now i can test job arguments like this:
/** #test */
public function test_jobs_arguments()
{
$this->app->bind(
RealJob::class,
function($app, $args){
// assertions against arguments
$this->assertEquals("argument", $args["arg"]);
$this->assertEquals([], $args["arg2"]);
return new FakeJob;
}
);
// System under test
dispatch_from_ioc(RealJob::class, ["arg" => "argument", "arg2" => []]);
}
Fake Job class
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class FakeJob extends Job
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct() {}
public function handle() {}
}
Does it makes sense? :)

Pass data to Mail Job/Queue - Lumen/Laravel

I'm using Lumen and want to know how to pass data to my job class.
I have my job class like below;
<?php
namespace App\Jobs;
use App;
use Illuminate\Contracts\Mail\Mailer;
class TestEmailJob extends Job
{
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* #return void
*/
public function handle(Mailer $mailer)
{
//
$data; // I want to pass this from my function
$mailer->queue('emails.emailtemplate', $data , function ($message) {
$message->from('support#xxx.com', 'Laravel');
$message->to('xxx#gmail.com')->cc('xxx#yahoo.co.uk');
});
}
}
I then have a function to push the job on the queue;
public function emailTest () {
$data = ['user' => $user];
Queue::push(new TestEmailJob);
}
How can I pass $data and receive it and use it in the job class?
You can instantiate the variable by passing to the constructor
class TestEmailJob extends Job implements SelfHandling, ShouldQueue
{
use InteractsWithQueue;
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function handle()
{
// $this->data;
}
}
Now from the Controller, you can call it like:
$this->dispatch(new TestEmailJob($data));
http://laravel.com/docs/5.1/queues#writing-job-classes

Resources