php 配置和测试Laravel任务调度

idfiyjo8  于 2022-10-30  发布在  PHP
关注(0)|答案(6)|浏览(187)

环境

  • Laravel版本:5.1.45(长期)
  • PHP版本:第5.6.1节

描述

我正在尝试使用Laravel任务调度每1分钟运行一个命令。

次尝试

我已将此行添加到我的cron选项卡文件中
$schedule->command('echo "Happy New Year!" ')->everyMinute();
这里是我的**/app/Console/Kernel.php**

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        \App\Console\Commands\Inspire::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('inspire')->hourly();
        $schedule->command('echo "Happy New Year!" ')->everyMinute(); //<---- ADD HERE        }
}

我添加了这一行$schedule->command('echo "Happy New Year!" ')->everyMinute();

问题

我该如何测试?
如何触发我的回声显示?
我怎么知道我做的是不是错了?

ht4b089n

ht4b089n1#

command()运行一个Artisan命令。您尝试实现的目标-向操作系统发出一个命令-由exec('echo "Happy New Year!"')完成
测试取决于您要测试的内容:

  • 调度程序(每分钟)是否正常工作?

在本例中,您不必这样做。它在原始框架代码中进行了测试。

  • 命令是否成功?

您可以手动运行php artisan schedule:run并查看输出。
预设情况下,排程器不会产生任何输出(>> /dev/null 2>&1)。不过,您可以链接writeOutputTo()appendOutputTo()(https://laravel.com/docs/5.1/scheduling#task-output),将执行命令档的输出重新导向至任何档案。
对于更复杂的逻辑,可以编写一个控制台命令(https://laravel.com/docs/5.1/artisan#writing-commands),并使用command()--这样就可以编写出漂亮的、可测试的代码。

a14dhokn

a14dhokn2#

如果你想对事件的调度进行单元测试你可以使用这个例子.它是基于默认的inspire命令:

public function testIsAvailableInTheScheduler()
{
    /**@var \Illuminate\Console\Scheduling\Schedule $schedule */
    $schedule = app()->make(\Illuminate\Console\Scheduling\Schedule::class);

    $events = collect($schedule->events())->filter(function (\Illuminate\Console\Scheduling\Event $event) {
        return stripos($event->command, 'YourCommandHere');
    });

    if ($events->count() == 0) {
        $this->fail('No events found');
    }

    $events->each(function (\Illuminate\Console\Scheduling\Event $event) {
        // This example is for hourly commands.
        $this->assertEquals('0 * * * * *', $event->expression);
    });
}
pokxtpni

pokxtpni3#

基于Michiel的答案,我使用了Illuminate\Console\Scheduling\Event中包含的方法来测试事件是否在给定的日期运行。
我已经使用Carbon::setTestNow()模拟了当前日期,这样when()skip()过滤器中任何基于日期的逻辑都将按预期的方式运行。

use Tests\TestCase;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\Event;

use Cron\CronExpression;
use Carbon\Carbon;

class ScheduleTest extends TestCase {

    public function testCompanyFeedbackSchedule()
    {
        $event = $this->getCommandEvent('your-command-signature');

        $test_date = Carbon::now()->startOfDay()->addHours(8);

        for ($i=0; $i < 365; $i++) { 
            $test_date->addDay();
            Carbon::setTestNow($test_date);

            // Run the when() & skip() filters
            $filters_pass = $event->filtersPass($this->app);
            // Test that the Cron expression passes
            $date_passes = $this->isEventDue($event);
            $will_run = $filters_pass && $date_passes;

            // Should only run on first friday of month
            if ($test_date->format('l') === 'Friday' && $test_date->weekOfMonth === 1) {
                $this->assertTrue($will_run, 'Task should run on '. $test_date->toDateTimeString());
            } else {
                $this->assertFalse($will_run, 'Task should not run on '. $test_date->toDateTimeString());
            }
        }
    }

    /**
     * Get the event matching the given command signature from the scheduler
     * 
     * @param  string  $command_signature
     * 
     * @return Illuminate\Console\Scheduling\Event
     */
    private function getCommandEvent($command_signature)
    {
        $schedule = app()->make(Schedule::class);

        $event = collect($schedule->events())->first(function (Event $event) use ($command_signature) {
            return stripos($event->command, $command_signature);
        });

        if (!$event) {
            $this->fail('Event for '. $command_signature .' not found');
        }

        return $event;
    }

    /**
     * Determine if the Cron expression passes.
     * 
     * Copied from the protected method Illuminate\Console\Scheduling\Event@isEventDue
     * 
     * @return bool
     */
    private function isEventDue(Event $event)
    {
        $date = Carbon::now();

        if ($event->timezone) {
            $date->setTimezone($event->timezone);
        }

        return CronExpression::factory($event->expression)->isDue($date->toDateTimeString());
    }
}
cwxwcias

cwxwcias4#

我在Laravel 8中运气不错,通过了以下测试:

public function testRunsAt930()
{
    Event::fake();
    $this->travelTo(now()->startOfWeek()->setHour(9)->setMinute(30));
    $this->artisan('schedule:run');

    Event::assertDispatched(ScheduledTaskFinished::class, function ($event) {
        return strpos($event->task->command, 'your-command-name') !== false;
    });
}

调度程序在成功运行调度时触发Illuminate\Console\Events\ScheduledTaskFinished事件,因此您可以通过模拟您的时间,然后实际运行调度,然后侦听该事件,来确定您的调度是否会在特定时间运行。
如果你不使用L8,你可能会使用一些像Carbonite的时间嘲笑,虽然我认为其余的应该工作,虽然你可能需要使用工匠门面在早期版本。
如果你想知道一个计划是否运行,你可以使用Event::assertDispatched()来代替ScheduledTaskFinished::class,或者监听ScheduledTaskFailed::class
我知道这个问题已经得到了解答,但是我发现如果你使用的是L8,甚至是更早的版本,这个方法可能会更干净一些。

ttcibm8c

ttcibm8c5#

构建在Michiel's anwer上也是一样,至少在L8上有区别。
而不是$event->command

$events = collect($schedule->events())->filter(function (Event $event) {
  return stripos($event->command, 'YourCommandHere');
});

需要$event->description

$events = collect($schedule->events())->filter(function (Event $event) {
  return stripos($event->description, 'YourCommandHere');
});

我在调查Tinker时发现了这一点:

>>> app()->make(\Illuminate\Console\Scheduling\Schedule::class)->events();
=> [
     Illuminate\Console\Scheduling\CallbackEvent {#3496
       +command: null,
       +expression: "* * * * *",
       +timezone: "UTC",
       +user: null,
       +environments: [],
       +evenInMaintenanceMode: false,
       +withoutOverlapping: false,
       +onOneServer: false,
       +expiresAt: 1440,
       +runInBackground: false,
       +output: "/dev/null",
       +shouldAppendOutput: false,
       +description: "App\Jobs\GenerateSuggestion",
       +mutex: Illuminate\Console\Scheduling\CacheEventMutex {#3498
         +cache: Illuminate\Cache\CacheManager {#282},
         +store: null,
       },
       +exitCode: null,
     },
   ]
lsmepo6l

lsmepo6l6#

您可以检查作业是否已添加到调度程序(L9):

$addedToScheduler = collect(App::make(Schedule::class)->events())
   ->pluck('description')
   ->contains(PaymentRenewJob::class);

$this->assertTrue($addedToScheduler, 'PaymentRenewJob is not added to scheduler');

您的代码的其余部分可以在控制台测试中进行测试。

$this->artisan('inspire')->assertSuccessful();

相关问题