diff --git a/src/Test/AggregateRootTestCase.php b/src/Test/AggregateRootTestCase.php index 8c8d365..826569e 100644 --- a/src/Test/AggregateRootTestCase.php +++ b/src/Test/AggregateRootTestCase.php @@ -7,6 +7,7 @@ use Closure; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; use Patchlevel\EventSourcing\CommandBus\HandlerFinder; +use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Attributes\After; use PHPUnit\Framework\Attributes\Before; use PHPUnit\Framework\Constraint\Exception as ExceptionConstraint; @@ -14,6 +15,7 @@ use PHPUnit\Framework\TestCase; use ReflectionClass; use Throwable; +use function sprintf; abstract class AggregateRootTestCase extends TestCase { @@ -26,7 +28,7 @@ abstract class AggregateRootTestCase extends TestCase /** @var array */ private array $expectedEvents = []; - /** @var class-string|null */ + /** @var class-string|null */ private string|null $expectedException = null; private string|null $expectedExceptionMessage = null; @@ -122,6 +124,8 @@ final public function assert(): self return $this; } + $this->expectedExceptionWasNotThrown(); + if (!$aggregate instanceof AggregateRoot) { throw new NoAggregateCreated(); } @@ -172,4 +176,34 @@ private function handleException(Throwable $throwable): void throw $throwable; } } + + private function expectedExceptionWasNotThrown(): void + { + if ($this->expectedException !== null) { + $this->numberOfAssertionsPerformed++; + throw new AssertionFailedError( + sprintf( + 'Failed asserting that exception "%s" is thrown', + $this->expectedException, + ), + ); + self::assertThat(null, new ExceptionConstraint($this->expectedException)); + } elseif ($this->expectedExceptionMessage !== null) { + $this->numberOfAssertionsPerformed++; + throw new AssertionFailedError( + sprintf( + 'Failed asserting that exception with message "%s" is thrown', + $this->expectedExceptionMessage, + ), + ); + self::assertThat( + null, + new ExceptionMessageIsOrContains($this->expectedExceptionMessage), + sprintf( + 'Failed asserting that exception with message "%s" is thrown', + $this->expectedExceptionMessage, + ), + ); + } + } } diff --git a/tests/Unit/Test/AggregateRootTestCaseTest.php b/tests/Unit/Test/AggregateRootTestCaseTest.php index eea79b1..73fdbfc 100644 --- a/tests/Unit/Test/AggregateRootTestCaseTest.php +++ b/tests/Unit/Test/AggregateRootTestCaseTest.php @@ -85,6 +85,71 @@ public function testExceptionAndMessage(): void self::assertSame(2, $test::getCount()); } + public function testExceptionNotThrown(): void + { + $test = $this->getTester(); + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->visitProfile(new VisitProfile(ProfileId::fromString('2'))), + ) + ->expectsException(ProfileError::class); + + try { + $test->assert(); + } catch (\Throwable $e) { + + } + self::assertSame(1, $test::getCount()); + } + + public function testExceptionNotThrownWithMessageSpecified(): void + { + $test = $this->getTester(); + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->visitProfile(new VisitProfile(ProfileId::fromString('2'))), + ) + ->expectsExceptionMessage('throwing so that you can catch it!'); + + $test->assert(); + self::assertSame(1, $test::getCount()); + } + + public function testExceptionNotThrownAndMessageSpecified(): void + { + $test = $this->getTester(); + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->visitProfile(new VisitProfile(ProfileId::fromString('2'))), + ) + ->expectsException(ProfileError::class) + ->expectsExceptionMessage('throwing so that you can catch it!'); + + $test->assert(); + self::assertSame(2, $test::getCount()); + } + public function testExceptionUncatched(): void { $test = $this->getTester();