我想测试该作业在某些情况下是否已被释放回队列中。
这是我的工作课程:
class ChargeOrder extends Job
{
use InteractsWithQueue, SerializesModels;
/**
* The order model which is to be charged
*/
protected $order;
/**
* The token or card_id which allows us to take payment
*/
protected $source;
/**
* Create a new job instance.
*
* @param App\Order $order;
* @param string $source;
* @return array
*/
public function __construct($order, $source)
{
$this->order = $order;
$this->source = $source;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(Charge $charge)
{
$result = $charge->execute($this->source, $this->order->totalInclVat());
$exception_errors = config('payment.errors.exception_errors');
// If we have an error that isn't caused by the user (anything but a card error)
// We're going to notify ourselves via slack so we can investigate.
if (array_key_exists('error', $result) && in_array($result['error']['code'], array_keys(config('payment.errors.other_error'))))
{
$client = new Client(config('services.slack.channels.payment_errors.url'), config('services.slack.channels.payment_errors.settings'));
$client->send(app()->environment() . ": " . $result['error']['code']);
}
// If the error is in the list of errors that throw an exception, then throw it.
if (array_key_exists('error', $result) && (in_array($result['error']['type'], $exception_errors) || in_array($result['error']['code'], $exception_errors)))
{
$status_code = config('payment.errors')[$result['error']['type']][$result['error']['code']]['status_code'];
$message = config('payment.errors')[$result['error']['type']][$result['error']['code']]['message'];
throw new BillingErrorException($status_code, $message);
}
// If we still have an error, then it something out of the user's control.
// This could be a network error, or an error with the payment system
// Therefore, we're going to throw this job back onto the queue so it can be processed later.
if (array_key_exists('error', $result) && in_array($result['error']['code'], array_keys(config('payment.errors.other_error'))))
{
$this->release(60);
}
}
}
我需要测试“$this->release(60)”在某些情况下是否被调用。
在我的测试中,我试图这样嘲笑工作合同:
// Set Up
$this->job = Mockery::mock('Illuminate\Contracts\Queue\Job');
$this->app->instance('Illuminate\Contracts\Queue\Job', $this->job);
然后
// During Test
$this->job->shouldReceive('release')->once();
但这不起作用。
大家有什么想法吗?
在分派作业之前,尝试在测试中添加以下内容:
Queue::after(function (JobProcessed $event) {
$this->assertTrue($event->job->isReleased());
});
上面的代码将在作业完成后被触发,并检查作业是否已被释放。
确保删除对
Queue::fake()
和 $this->expectsJob()
的任何调用,因为它们会阻止实际作业的执行。
我通过创建一个仅在作业释放回队列后才触发的事件解决了这个问题。然后在我的测试中,我可以在分派作业后使用事件模拟来监视该事件,并知道我们是否将其释放回队列中。
// In your job
$this->release();
event(new MyJobReleasedEvent()); // Every time you have a release() call
// In your Unit Test
Event::fake([MyJobReleasedEvent::class]);
dispatch(new MyJob();
Event::assertDispatched(MyJobReleasedEvent::class);
如果你想变得更奇特,我相信你可以连接自己的 Job 类,在调用 release() 时自动执行此操作,但我很少需要它,只需根据需要内联执行即可。
我发现测试作业是否已发布的最准确方法是模拟底层作业对象(每个使用 InteractsWithQueue 特征的作业都有它)。
// test.php
public function testReleaseJob()
{
$job = (new FooJob();
// mocking underling job object.
$job->job = \Mockery::mock(\Illuminate\Contracts\Queue\Job::class);
$job->job->shouldReceive('release')->once()->with(30);
$job->handle();
}
在我的例子中,FooJob 释放方法是手动调用的。
public function handle()
{
if ($this->invalidState()) {
$this->release(30); // try again in 30 seconds
} else {
$this->doTheThing(); /
}
}