Проблема sleep(): код з паузами (очікування між повторами, обмеження частоти запитів до API) робить тести повільними, а перевірити, скільки саме чекав код, неможливо.
Клас Sleep - обгортка над sleep/usleep, яку можна підробити в тестах:
use Illuminate\Support\Sleep;
Sleep::for(500)->milliseconds();
Sleep::for(2)->seconds();
Sleep::until(now()->addMinute());
// між запитами до API з лімітом частоти
foreach ($pages as $page) {
$client->fetch($page);
Sleep::for(1)->second();
}
У тесті:
use Illuminate\Support\Sleep;
Sleep::fake();
$importer->run();
Sleep::assertSlept(fn (Carbon\CarbonInterval $d) => $d->totalSeconds === 1, times: 3);
Sleep::assertSequence([
Sleep::for(1)->second(),
Sleep::for(2)->seconds(),
]);
Sleep::assertNeverSlept();
Тест проходить миттєво, а затримки перевіряються явно. Sleep::fake(syncWithCarbon: true) ще й пересуває «поточний час» Carbon на тривалість паузи.
Бонус: хелпер retry() під капотом чекає через Sleep, тож Sleep::fake() робить миттєвими й тести з повторними спробами.
Benchmark - швидко порівняти варіанти коду:
use Illuminate\Support\Benchmark;
Benchmark::dd([
'eager' => fn () => Post::with('author')->get(),
'lazy' => fn () => Post::all()->each->author,
], iterations: 10);
// ["eager" => "12.3ms", "lazy" => "48.7ms"]
$ms = Benchmark::measure(fn () => $report->build()); // середній час у мс
[$result, $ms] = Benchmark::value(fn () => $report->build()); // результат і час
Обмеження Benchmark:
- це мікробенчмарк у поточному процесі: кеш бази, OPcache, прогрів впливають на результат. Перша ітерація часто повільніша - тому
iterations; - для продакшен-продуктивності потрібні профілювальники й моніторинг (Xdebug, Blackfire, Pulse, APM), а не
Benchmark::dd; Benchmark::dd()зупиняє виконання - лише для локального налагодження.
Benchmark::value() корисний і в продакшен-коді: повертає результат разом з тривалістю, яку можна записати в лог чи метрику для повільних операцій.