Configure and Test Laravel Task Scheduling

后端 未结 3 1528
栀梦
栀梦 2020-12-17 16:10

Environment

  • Laravel Version : 5.1.45 (LTS)

  • PHP Version : 5.6.1


Description

相关标签:
3条回答
  • 2020-12-17 16:27

    If you want to unit test the scheduling of events you can use this example. It is based on the default inspire command:

    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);
        });
    }
    
    0 讨论(0)
  • 2020-12-17 16:32

    Building on Michiel's answer, I've used the methods contained in Illuminate\Console\Scheduling\Event to test if the event is due to run for a given date.

    I've mocked the current date using Carbon::setTestNow() so that any date based logic in the when() and skip() filters will behave as expected.

    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());
        }
    }
    
    0 讨论(0)
  • 2020-12-17 16:33

    command() runs an artisan command. What you're trying to achieve - issuing a command to the OS - is done by exec('echo "Happy New Year!"')

    Testing depends on what you want to test:

    • Whether the scheduler (every minute) is working?

    In this case, you don't have to. It is tested in the original framework code.

    • Whether the command succeeds?

    Well, you can manually run php artisan schedule:run and see the output.

    The scheduler does not produce any output on default (>> /dev/null 2>&1). You can, however, redirect the output of the runned scripts to any file by chaining writeOutputTo() or appendOutputTo() (https://laravel.com/docs/5.1/scheduling#task-output).


    For more complex logic, write a console command instead (https://laravel.com/docs/5.1/artisan#writing-commands) and use command() - this way you can write nice, testable code.

    0 讨论(0)
提交回复
热议问题