M1: CRUD-Slice 'Mahlzeit' Schritt 1 – Logik + Daten + Tests
Rich-Model Mahlzeit (MahlzeitStatus, Wochentag) mit Invarianten und Zustandsübergängen; DTOs + MahlzeitFactory (reine Mapping-Funktionen); Manager (create hängt an Ende an: maxSortOrder+1, find → 404) und Create/Update/Delete-UseCases mit Transaktion + Events nach Commit. Data-Layer: MahlzeitEntity (Tabelle essens_mahlzeiten, wochentage als CSV), Mapper (CSV/Enum/null), Provider (find/list/maxSortOrder), Processor (create/save/delete). DI-Bindings in services.yaml. ClockInterface (Logic) + SystemClock (Data). Tests: Model/Factory/UseCase-Unit + Provider/Processor/Mapper-Integration (In-Mem-SQLite). composer test grün (53 Tests, 161 Assertions).
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Logic\Essen\Mapping;
|
||||
|
||||
use App\Logic\Common\Exception\BusinessRuleViolationException;
|
||||
use App\Logic\Essen\Dto\MahlzeitCreateRequest;
|
||||
use App\Logic\Essen\Dto\MahlzeitUpdateRequest;
|
||||
use App\Logic\Essen\Mapping\MahlzeitFactory;
|
||||
use App\Logic\Essen\Model\Mahlzeit;
|
||||
use App\Logic\Essen\Model\MahlzeitStatus;
|
||||
use App\Logic\Essen\Model\Wochentag;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class MahlzeitFactoryTest extends TestCase
|
||||
{
|
||||
private function factory(): MahlzeitFactory
|
||||
{
|
||||
return new MahlzeitFactory();
|
||||
}
|
||||
|
||||
private function jetzt(): \DateTimeImmutable
|
||||
{
|
||||
return new \DateTimeImmutable('2026-09-18 12:00:00');
|
||||
}
|
||||
|
||||
public function testCreateFromCreateRequest(): void
|
||||
{
|
||||
$jetzt = $this->jetzt();
|
||||
$req = new MahlzeitCreateRequest(
|
||||
name: 'Pasta',
|
||||
notiz: 'vegan',
|
||||
wochentage: [Wochentag::Fr, Wochentag::Sa],
|
||||
);
|
||||
|
||||
$m = $this->factory()->createFromCreateRequest($req, $jetzt);
|
||||
|
||||
self::assertSame(0, $m->id);
|
||||
self::assertSame('Pasta', $m->name);
|
||||
self::assertSame('vegan', $m->notiz);
|
||||
self::assertSame([Wochentag::Fr, Wochentag::Sa], $m->wochentage());
|
||||
self::assertSame(0, $m->sortOrder);
|
||||
self::assertSame(MahlzeitStatus::Geplant, $m->status);
|
||||
self::assertSame($jetzt, $m->erstelltAm);
|
||||
self::assertSame($jetzt, $m->aktualisiertAm);
|
||||
}
|
||||
|
||||
public function testCreateWithLeerenNameWirft(): void
|
||||
{
|
||||
$req = new MahlzeitCreateRequest(name: ' ');
|
||||
|
||||
$this->expectException(BusinessRuleViolationException::class);
|
||||
|
||||
$this->factory()->createFromCreateRequest($req, $this->jetzt());
|
||||
}
|
||||
|
||||
public function testUpdateÄndertNurGelieferteFelder(): void
|
||||
{
|
||||
$vorher = new Mahlzeit(
|
||||
id: 7,
|
||||
name: 'Altes',
|
||||
notiz: 'alte Notiz',
|
||||
wochentage: [Wochentag::Mo],
|
||||
sortOrder: 3,
|
||||
status: MahlzeitStatus::Geplant,
|
||||
erstelltAm: $this->jetzt(),
|
||||
aktualisiertAm: $this->jetzt(),
|
||||
gegessenAm: null,
|
||||
);
|
||||
|
||||
$req = new MahlzeitUpdateRequest(name: 'Neues', wochentage: [Wochentag::Do]);
|
||||
|
||||
$nachher = $this->factory()->updateFromUpdateRequest($vorher, $req, $this->jetzt());
|
||||
|
||||
self::assertSame('Neues', $nachher->name);
|
||||
self::assertSame([Wochentag::Do], $nachher->wochentage());
|
||||
self::assertSame('alte Notiz', $nachher->notiz, 'nicht geliefertes Feld bleibt unverändert');
|
||||
self::assertSame(3, $nachher->sortOrder);
|
||||
self::assertSame(7, $nachher->id);
|
||||
}
|
||||
|
||||
public function testUpdateMitNullFeldBelässtBestandwert(): void
|
||||
{
|
||||
$vorher = new Mahlzeit(7, 'Altes', 'Notiz', [Wochentag::Mo], 3, MahlzeitStatus::Geplant, $this->jetzt(), $this->jetzt(), null);
|
||||
|
||||
$nachher = $this->factory()->updateFromUpdateRequest($vorher, new MahlzeitUpdateRequest(), $this->jetzt());
|
||||
|
||||
self::assertSame('Altes', $nachher->name);
|
||||
self::assertSame('Notiz', $nachher->notiz);
|
||||
self::assertSame([Wochentag::Mo], $nachher->wochentage());
|
||||
}
|
||||
|
||||
public function testUpdateMitLeerenNameWirft(): void
|
||||
{
|
||||
$vorher = new Mahlzeit(7, 'Altes', '', [], 0, MahlzeitStatus::Geplant, $this->jetzt(), $this->jetzt(), null);
|
||||
|
||||
$this->expectException(BusinessRuleViolationException::class);
|
||||
|
||||
$this->factory()->updateFromUpdateRequest($vorher, new MahlzeitUpdateRequest(name: ' '), $this->jetzt());
|
||||
}
|
||||
|
||||
public function testUpdateLeereWochentageListeSetztKeineTage(): void
|
||||
{
|
||||
$vorher = new Mahlzeit(7, 'Altes', '', [Wochentag::Mo], 0, MahlzeitStatus::Geplant, $this->jetzt(), $this->jetzt(), null);
|
||||
|
||||
$nachher = $this->factory()->updateFromUpdateRequest($vorher, new MahlzeitUpdateRequest(wochentage: []), $this->jetzt());
|
||||
|
||||
self::assertSame([], $nachher->wochentage());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user