How to test job arguments in Laravel? - 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? :)

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

issue in mailable and queue in laravel

i am not able pass form data to job from controller in laravel
below is my controller
public function sendmail_action(Request $request){
try{
$data=$request->all();
$this->dispatch(new LeadSendmailJob($data));
return response()->json(['status'=>'true']);
}catch (\Exception $e){
return response()->json(['status'=>'false','msg'=>$e->getMessage()]);
}
}
below is job
<?php
namespace App\Jobs;
use App\Mail\LeadMail;
use Illuminate\Bus\Queueable;
use Illuminate\Http\Request;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Mail;
class LeadSendmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public $data;
public function __construct(array $data)
{
$this->data=$data;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Mail::to('sdf#gmail.com')->send(new LeadMail($this->data));
}
}
and below is mail
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class LeadMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $data;
public function __construct(array $data)
{
$this->data=$data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('frontend.emails.lead-mail')
->from('info#nextaussietech.com')
->with(['message'=>$this->data->message]);
}
}
in failed job table i am getting this exception
ErrorException: Trying to get property 'message' of non-object in C:\xampp\htdocs\CRM\app\Mail\LeadMail.php:34
it works while using model data but its not working when i am passing form data
$data isn't an object, it is an array; Request::all() returns an array. You can't access an array with the same notation you would an object.
$this->data['message']; // access element of the array

Creating Email queue in Laravel

Newsletter.php
<?php
namespace App\Mail;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Http\Request;
class Newsletter extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $order;
public function __construct($order)
{
$this->order = $order;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('mail', $this->order)->subject($this->order['subject']);
}
}
SendReminderEmail.php
<?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;
use Mail;
use App\Mail\Newsletter;
use App\User;
class SendReminderEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public $order, $email;
public function __construct($order, $emails)
{
$this->order = $order;
$this->email = $emails;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//for($i=0;$i<count($this->email);$i++)
Mail::to($this->email)->queue(new Newsletter($this->order));
}
}
Controller
public function sendSubMail(Request $request){
$data = ['text' => $request->input('message'), 'subject' => $request->input('subject')];
$emails = DB::table('emails')->get();
for ($i=0; $i < count($emails); $i++) {
try {
Mail::to($emails[$i])->queue(new Newsletter($data));
//dispatch((new Job)->onQueue('high'))
dispatch(new SendReminderEmail($data, $emails[$i]));
} catch (Exception $e) {
}
}
return view('emailSent', ['sub' => 'Emails successfully sent']);
}
Can anyone explain me how to create an Email queue in laravel. I tried many ways but none of them seems to work.
I'm trying to send email using queues. I have to send more than 1500 in the request. but the queue which I implemented doesnt seem to work. Please help.
Thanks in advance
Using Cron to send mail One Method

laravel queue not working like it did before

Hello i was working with mailable and using queue but when i used php artisan queue:listen and send a mail it did not work like it was supposed to do, i did get the email on mailtrap, but there was no message in my console. I tried sending the mail first and then use my command but it worked without my command. and it does not take a while because its sending immediately here is my code
controller.php
use Illuminate\Support\Facades\Mail;
use App\Mail\testmail;
class Controller extends Controller{
public function email($email, Request $request){
$emailuser = $request->input('email');
$message = $request->input('bericht');
mail::to($email)->queue(new testmail($emailuser, $message));
}
}
testmail.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class testmail extends Mailable
{
use Queueable, SerializesModels;
public $emailuser;
public $message;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($emailuser, $message)
{
$this->emailuser = $emailuser;
$this->message = $message;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('email.mail');
}
}
mail.blade.php
#component('mail::message')
{{ $emailuser }}
{{ $message }}
Thanks,<br>
{{ config('app.name') }}
#endcomponent
does anyone know how to fixs this because i need it to have a delay for my application
Use a job instead of Maillable and in that job in handle function write down the code to send the email in that job
for i.e-:
$job = (new SendWelcomeEmail($activation->code,$user))->onQueue('default');
and the job file SendwelcomeEmail would like following-:
<?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;
use App\Jobs\Job;
use Mail;
class SendWelcomeEmail extends Job implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
protected $activation_code;
protected $user;
public function __construct($activation_code,$user)
{
$this->activation_code=$activation_code;
$this->user=$user;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
try{
$user=$this->user;
Mail::send('emails.user.register', ['activation_code' => $this->activation_code,'user'=>$this->user], function ($m) use ($user) {
$m->to($user->email,$user->first_name." ".$user->last_name)
->subject(trans('emails.USER_REGISTER_SUBJECT',['project'=>trans('project.project_name')]));
});
\Log::useDailyFiles(storage_path().'/logs/user-registration/success/'.date('Y-m-d').'.log');
\Log::info('Welcome Email Send to-:'.$user->email);
}catch(Exception $ex){
\Log::useDailyFiles(storage_path().'/logs/user-registration/error/'.date('Y-m-d').'.log');
\Log::error($ex->getMessage());
\Log::error("Line Number->".$ex->getLine());
}
}
}

Laravel Websocket, and Queue Error (Serialization of 'Closure' is not allowed)

Im currently having a problem where I can't queue a job inside a websocket server, my objective is to fire a background job in a specified date and time
I'm having an error that says "An error has occurred: Serialization of 'Closure' is not allowed"
here's is my current code
<?php namespace App;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use App\Http\Controllers\WinIt;
use Cache;
use Carbon\Carbon;
use Session;
use Queue;
// Command Classes
use App\Commands\WinItInit;
class WebsocketServer implements MessageComponentInterface {
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
// Fire event when current date and time reaches $datetime
$datetime = '2016-02-10 15:48:08';
$serialization = Queue::later($datetime, new WinItInit($conn, $this->clients));
}
}
// The command to fire
<?php namespace App\Commands\WinIt;
use App\Commands\Command;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldBeQueued;
// Class Aliases
use DB;
use Input;
use Queue;
use Request;
use Response;
use Session;
use URL;
use Illuminate\Http\Exception;
use Illuminate\Support\Facades\Artisan;
// Custom Classes
class WinItInit extends Command implements SelfHandling, ShouldBeQueued {
use InteractsWithQueue, SerializesModels;
private $from = null;
private $clients = null;
/**
* Create a new command instance.
*
* #return void
*/
public function __construct($from = null, $clients = null)
{
$this->from = $from;
$this->clients = $clients;
$this->type = 'sample';
}
/**
* Execute the command.
*
* #return void
*/
public function handle()
{
$data = array();
switch ($this->type)
{
case 'sample':
$datetime = date('Y-m-d H:i:s', time());
break;
}
foreach ($this->clients as $client)
{
$client->send(json_encode($data));
}
}
}

Resources