Testovanie
OpeningHours::fake() zaznamená každý zápis — cez fasádu, injektovaný manažér, save() buildera aj trait vlastníka — bez zásahu do databázy, bez udalostí a bez materializácie intervalov. Každý zápis však stále prejde skutočnými kontrolami manažéra voči aktuálnemu stavu databázy — validácia vstupu, kľúč kalendára, uložený vlastník, limity, cudzie id, expectedRevision a CalendarNotFoundException pri zápise výnimky bez kalendára —, takže test zlyhá tam, kde by zlyhala produkcia. Čítania naďalej idú do databázy, takže fakovaný zápis ďalší zápis nevidí:
use RoundlyConsulting\OpeningHours\DataTransferObjects\CalendarData;
use RoundlyConsulting\OpeningHours\DataTransferObjects\ExceptionData;
use RoundlyConsulting\OpeningHours\Facades\OpeningHours;
$fake = OpeningHours::fake();
$this->post("/clinics/{$clinic->id}/holidays", ['date' => '2026-12-24']);
$fake->assertExceptionAdded($clinic, callback: fn (ExceptionData $data) => $data->label === 'Holiday');
$fake->assertNothingSynced();
// The owner trait and the builder are recorded too:
$clinic->setOpeningHours(['week' => ['monday' => ['09:00-17:00']]], 'pickup');
OpeningHours::delete($clinic, force: true);
$fake->assertSynced($clinic, 'pickup', fn (CalendarData $data) => count($data->schedules) === 1);
$fake->assertDeleted($clinic, force: true);
OpeningHours::assertNothingRefreshed(); // every assertion also works statically| Asercia | Prejde, keď | Opak |
|---|---|---|
assertSynced($owner, ?$calendar, ?fn (CalendarData): bool) | Zhodoval sa sync — cez fasádu, save() buildera, setOpeningHours() alebo editOpeningHours()->save(). | assertNothingSynced() |
assertExceptionAdded($owner, ?$calendar, ?fn (ExceptionData): bool) | Zhodovalo sa exceptions()->add(), closed() alebo open(). | assertNoExceptionsAdded() |
assertExceptionRemoved($owner, ?int $ruleId, ?$calendar) | Zhodovalo sa exceptions()->remove(). | assertNoExceptionsRemoved() |
assertDeleted($owner, ?$calendar, ?bool $force) | Zhodovalo sa delete() — vrátane kaskády pri zmazaní vlastníka, zaznamenanej ako force: true. | assertNothingDeleted() |
assertRefreshed($owner, ?$calendar) | Zhodovalo sa refresh(). | assertNothingRefreshed() |
| — | Nezaznamenal sa žiadny zápis. | assertNothingWritten() |
Kalendár null znamená predvolený; vlastníci sa porovnávajú cez Model::is(). Každá asercia funguje aj staticky (OpeningHours::assertSynced($clinic)) a writes() vráti zoznam zaznamenaných RecordedWrite — operáciu, vlastníka, kalendár a payload — na vlastné kontroly. Pod fake vráti sync() OpeningHours v pamäti, exceptions()->add(), closed() a open() neuložené ExceptionRule a remove() aj delete() vrátia true. Ak skutočný manažér nemá čo robiť, fake odpovie rovnako a nič nezaznamená: delete() aj exceptions()->remove() vrátia false a refresh() chýbajúceho kalendára nerobí nič. Revízne hooky pri priamych úpravách riadkov sa nefakujú.
Nad skutočnými riadkami
„Teraz“ pochádza z fasády Date v Laraveli, takže čas zmrazíte cez CarbonImmutable::setTestNow() alebo travelTo() a overujete cez verejné API:
use Carbon\CarbonImmutable;
use RoundlyConsulting\OpeningHours\OpeningHours;
afterEach(fn () => CarbonImmutable::setTestNow());
it('reports the clinic as open on Monday morning', function (): void {
CarbonImmutable::setTestNow(CarbonImmutable::parse('2026-09-28 10:00', 'Europe/Bratislava'));
$clinic = Clinic::factory()->create();
$clinic->setOpeningHours([
'timezone' => 'Europe/Bratislava',
'week' => ['monday' => ['08:00-12:00', '13:00-17:00']],
]);
expect($clinic->openingHours()->isOpen())->toBeTrue()
->and($clinic->openingHours()->nextClose()?->format('H:i'))->toBe('12:00');
});
it('previews overnight hours without a database', function (): void {
$preview = OpeningHours::make(['week' => ['saturday' => ['22:00-03:00']]], 'Europe/Bratislava');
expect($preview->isOpenAt(CarbonImmutable::parse('2026-10-04 01:00', 'Europe/Bratislava')))->toBeTrue();
});Bez fake naplňte hodiny cez OpeningHours::sync() alebo setOpeningHours() — prebehne rovnaká validácia ako v produkcii — alebo cez factories modelov v RoundlyConsulting\OpeningHours\Database\Factories: CalendarFactory (forOwner(), timezone(), key()), ScheduleFactory (base(), seasonal()), ScheduleRangeFactory (on(), between()), ExceptionRuleFactory (closed(), on(), yearly()), ExceptionRangeFactory (between()) a IntervalFactory.
OpeningHours::make() nepotrebuje databázu vôbec — ideálne pre unit testy vykresľovania alebo logiky slotov. Vlastná testovacia sada balíka beží nad SQLite, PostgreSQL aj MySQL.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.