Created
January 29, 2020 13:51
-
-
Save Ocramius/085d4c59f491c19442ba511623834d77 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Test\Feature; | |
use Shared\Domain\DomainEvent; | |
use Shared\Domain\EventSourcedAggregateRoot; | |
use Webmozart\Assert\Assert; | |
use function array_shift; | |
/** | |
* This class is designed for inheritance, and provides facilities to test a generic {@see EventSourcedAggregateRoot}. | |
* | |
* @psalm-template TestedAggregateRootType of EventSourcedAggregateRoot | |
*/ | |
abstract class EventSourcedAggregateContext | |
{ | |
/** | |
* @var DomainEvent[] | |
* @psalm-var list<DomainEvent> | |
*/ | |
private array $pastHistory = []; | |
/** | |
* @var DomainEvent[]|null | |
* @psalm-var null|list<DomainEvent> | |
*/ | |
private ?array $recordedEvents = null; | |
/** @psalm-var TestedAggregateRootType|null */ | |
private ?EventSourcedAggregateRoot $aggregateRoot = null; | |
/** @AfterScenario */ | |
final public function ensure_no_further_events_were_recorded() : void | |
{ | |
Assert::isEmpty($this->recordedEvents); | |
} | |
/** @psalm-return class-string<TestedAggregateRootType> */ | |
abstract protected function aggregateRootClassName() : string; | |
/** @psalm-param TestedAggregateRootType $aggregateRoot */ | |
final protected function useManuallyCreatedAggregateRoot(EventSourcedAggregateRoot $aggregateRoot) : void | |
{ | |
Assert::null( | |
$this->aggregateRoot, | |
'You are replacing a pre-existing aggregate root: why are there two aggregates in your test?' | |
); | |
$this->aggregateRoot = $aggregateRoot; | |
} | |
final protected function givenPastEvent(DomainEvent $event) : void | |
{ | |
$this->pastHistory[] = $event; | |
} | |
/** | |
* @psalm-template ExpectedEventType of DomainEvent | |
* @psalm-param class-string<ExpectedEventType> $expectedEventType | |
* @psalm-return ExpectedEventType | |
*/ | |
final protected function expectNextRecordedEvent(string $expectedEventType) : DomainEvent | |
{ | |
if ($this->recordedEvents === null) { | |
$this->recordedEvents = $this->getOrReconstituteAggregateRoot()->popRecordedEvents(); | |
} | |
$event = array_shift($this->recordedEvents); | |
Assert::isInstanceOf($event, $expectedEventType); | |
return $event; | |
} | |
/** @psalm-return TestedAggregateRootType */ | |
final protected function getOrReconstituteAggregateRoot() : EventSourcedAggregateRoot | |
{ | |
return $this->aggregateRoot | |
?? $this->aggregateRoot = $this->aggregateRootClassName()::reconstituteFromHistory($this->pastHistory); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment