- Added BrandCreated event to encapsulate brand creation details. - Created LogBrandCreated listener to log brand creation events. - Updated BrandResolver to dispatch BrandCreated event upon new brand creation. - Introduced EventServiceProvider to register event listeners. - Added unit tests for BrandCreated event and LogBrandCreated listener.
119 lines
4.3 KiB
PHP
119 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Domain\Services;
|
|
|
|
use Domain\Events\BrandCreated;
|
|
use Domain\Exceptions\BrandNotFoundException;
|
|
use Domain\Models\Entities\Brand;
|
|
use Domain\Models\ValueObjects\Brand\ArcadiaBrand;
|
|
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
|
use Domain\Models\ValueObjects\Brand\BrandCode;
|
|
use Domain\Models\ValueObjects\Brand\BrandId;
|
|
use Domain\Models\ValueObjects\Brand\BrandName;
|
|
use Domain\Services\BrandCodeGenerator;
|
|
use Domain\Services\BrandResolver;
|
|
use Infra\Adapters\Directories\InMemoryArcadiaBrandDirectory;
|
|
use Infra\Adapters\Repositories\InMemoryBrandRepository;
|
|
use Ramsey\Uuid\Uuid;
|
|
use Shared\DDD\Event\DomainEventDispatcher;
|
|
use Shared\DDD\Event\Event;
|
|
|
|
covers(BrandResolver::class);
|
|
|
|
describe('BrandResolver Unit Tests', function (): void {
|
|
$arcadiaDirectory = new InMemoryArcadiaBrandDirectory();
|
|
$brandRepository = new InMemoryBrandRepository();
|
|
$codeGenerator = new BrandCodeGenerator();
|
|
|
|
beforeEach(function () use ($arcadiaDirectory, $brandRepository): void {
|
|
$arcadiaDirectory->clear();
|
|
$brandRepository->clear();
|
|
});
|
|
|
|
it('returns existing brand if already present in repository without dispatching event', function () use ($arcadiaDirectory, $brandRepository, $codeGenerator): void {
|
|
// GIVEN
|
|
$existing = Brand::hydrate(
|
|
id: new BrandId(Uuid::uuid7()),
|
|
name: new BrandName('Le Gaulois'),
|
|
code: new BrandCode('LGL01'),
|
|
arcadiaId: new ArcadiaId(1),
|
|
);
|
|
$brandRepository->add($existing);
|
|
|
|
$dispatcher = new class () implements DomainEventDispatcher
|
|
{
|
|
/** @var list<Event> */
|
|
public array $dispatched = [];
|
|
|
|
public function dispatch(Event $event): void
|
|
{
|
|
$this->dispatched[] = $event;
|
|
}
|
|
};
|
|
|
|
$resolver = new BrandResolver($arcadiaDirectory, $brandRepository, $codeGenerator, $dispatcher);
|
|
|
|
// WHEN
|
|
$resolved = $resolver->resolve(new ArcadiaId(1));
|
|
|
|
// THEN
|
|
expect($resolved)->toBe($existing)
|
|
->and($dispatcher->dispatched)->toBeEmpty();
|
|
});
|
|
|
|
it('generates, persists and dispatches BrandCreated event when brand is not in repository but in Arcadia directory', function () use ($arcadiaDirectory, $brandRepository, $codeGenerator): void {
|
|
// GIVEN
|
|
$arcadiaDirectory->add(new ArcadiaBrand(new ArcadiaId(2), new BrandName('Maître CoQ')));
|
|
|
|
$dispatcher = new class () implements DomainEventDispatcher
|
|
{
|
|
/** @var list<Event> */
|
|
public array $dispatched = [];
|
|
|
|
public function dispatch(Event $event): void
|
|
{
|
|
$this->dispatched[] = $event;
|
|
}
|
|
};
|
|
|
|
$resolver = new BrandResolver($arcadiaDirectory, $brandRepository, $codeGenerator, $dispatcher);
|
|
|
|
// WHEN
|
|
$resolved = $resolver->resolve(new ArcadiaId(2));
|
|
|
|
// THEN
|
|
expect($resolved->arcadiaId->value)->toBe(2)
|
|
->and($resolved->name->value)->toBe('Maître CoQ')
|
|
->and(str_starts_with($resolved->code->value, 'MCQ'))->toBeTrue();
|
|
|
|
expect($brandRepository->findByArcadiaId(new ArcadiaId(2)))->not->toBeNull();
|
|
|
|
expect($dispatcher->dispatched)->toHaveCount(1)
|
|
->and($dispatcher->dispatched[0])->toBeInstanceOf(BrandCreated::class);
|
|
|
|
/** @var BrandCreated $event */
|
|
$event = $dispatcher->dispatched[0];
|
|
expect($event->arcadiaId->value)->toBe(2)
|
|
->and($event->brandName->value)->toBe('Maître CoQ')
|
|
->and($event->brandCode->value)->toBe($resolved->code->value)
|
|
->and($event->brandId->value)->toBe($resolved->id->value);
|
|
});
|
|
|
|
it('throws BrandNotFoundException when resolving an unknown ArcadiaId', function () use ($arcadiaDirectory, $brandRepository, $codeGenerator): void {
|
|
// GIVEN
|
|
$dispatcher = new class () implements DomainEventDispatcher
|
|
{
|
|
public function dispatch(Event $event): void
|
|
{
|
|
}
|
|
};
|
|
|
|
$resolver = new BrandResolver($arcadiaDirectory, $brandRepository, $codeGenerator, $dispatcher);
|
|
|
|
// WHEN & THEN
|
|
expect(fn () => $resolver->resolve(new ArcadiaId(999)))
|
|
->toThrow(BrandNotFoundException::class, 'Arcadia brand with ID 999 not found.');
|
|
});
|
|
});
|