From e6d40431f74f24243b9ea438240e1e1066553459 Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Mon, 16 Feb 2026 10:35:22 +0100 Subject: [PATCH 1/7] feat: support closure callbacks in then() for aggregate state assertions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend then() to accept Closure callbacks alongside event objects. Closures receive the aggregate instance and are executed after the event equality assertion, enabling assertions on aggregate state set by apply methods. The method signature remains `then(object ...$events)` — since Closure is a subclass of object in PHP, this is not a BC break and requires no changes to existing consumer code. Only the internal property was renamed from $expectedEvents to $thenArguments (private scope). Event order is preserved regardless of callback placement: closures are filtered out before comparison, and the remaining event objects are compared in their original relative order. When only closures are passed (no event objects), the event assertion still runs against an empty array, strictly asserting that zero events were emitted. This is a deliberate design decision to keep the behaviour explicit. Closes #20 --- src/Test/AggregateRootTestCase.php | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Test/AggregateRootTestCase.php b/src/Test/AggregateRootTestCase.php index 8c8d365..c8e6059 100644 --- a/src/Test/AggregateRootTestCase.php +++ b/src/Test/AggregateRootTestCase.php @@ -15,6 +15,9 @@ use ReflectionClass; use Throwable; +use function array_filter; +use function array_values; + abstract class AggregateRootTestCase extends TestCase { /** @var array */ @@ -24,8 +27,9 @@ abstract class AggregateRootTestCase extends TestCase /** @var array */ private array $parameters = []; - /** @var array */ - private array $expectedEvents = []; + /** @var array */ + private array $thenExpectations = []; + /** @var class-string|null */ private string|null $expectedException = null; private string|null $expectedExceptionMessage = null; @@ -49,9 +53,14 @@ final public function when(object $callable, mixed ...$parameters): self return $this; } + /** + * @param object|Closure(object): void ...$events Expected events and/or callbacks for aggregate state assertions. + * Closures receive the aggregate instance and are executed after event assertions. + * Event order is preserved regardless of callback placement. + */ final public function then(object ...$events): self { - $this->expectedEvents = $events; + $this->thenExpectations = $events; return $this; } @@ -126,9 +135,16 @@ final public function assert(): self throw new NoAggregateCreated(); } + $expectedEvents = array_values(array_filter($this->thenExpectations, static fn (object $item) => !$item instanceof Closure)); + $expectationCallbacks = array_filter($this->thenExpectations, static fn (object $item) => $item instanceof Closure); + $events = $aggregate->releaseEvents(); - self::assertEquals($this->expectedEvents, $events, 'The events doesn\'t match the expected events.'); + self::assertEquals($expectedEvents, $events, 'The events doesn\'t match the expected events.'); + + foreach ($expectationCallbacks as $callback) { + $callback($aggregate); + } return $this; } @@ -139,7 +155,7 @@ final public function reset(): void $this->givenEvents = []; $this->when = null; $this->parameters = []; - $this->expectedEvents = []; + $this->thenExpectations = []; $this->expectedException = null; $this->expectedExceptionMessage = null; } From 1ec6971d1d37385058a82e4249889597a6d710b4 Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Mon, 16 Feb 2026 10:35:31 +0100 Subject: [PATCH 2/7] test: add test cases for then() closure callbacks Cover the following scenarios: - testThenWithEventAndCallback: event + callback in then() - testThenWithCallbackMixedBetweenEvents: callback placed before event - testThenWithMultipleCallbacks: multiple callbacks with one event - testThenWithCallbackOnCreation: callback during aggregate creation - testThenWithOnlyCallbacks: only callbacks, asserting zero events Add emitsNoEvents() no-op method to Profile fixture to support the only-callbacks test scenario. --- tests/Unit/Fixture/Profile.php | 4 + tests/Unit/Test/AggregateRootTestCaseTest.php | 135 ++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/tests/Unit/Fixture/Profile.php b/tests/Unit/Fixture/Profile.php index e6df059..2d02333 100644 --- a/tests/Unit/Fixture/Profile.php +++ b/tests/Unit/Fixture/Profile.php @@ -28,6 +28,10 @@ public function email(): Email return $this->email; } + public function emitsNoEvents(): void + { + } + #[Handle] public static function createProfile(CreateProfile $createProfile): self { diff --git a/tests/Unit/Test/AggregateRootTestCaseTest.php b/tests/Unit/Test/AggregateRootTestCaseTest.php index eea79b1..9d4b486 100644 --- a/tests/Unit/Test/AggregateRootTestCaseTest.php +++ b/tests/Unit/Test/AggregateRootTestCaseTest.php @@ -349,6 +349,141 @@ public function testVisitedWithCommandWithParams(): void self::assertSame(1, $test::getCount()); } + public function testThenWithEventAndCallback(): void + { + $test = $this->getTester(); + $called = false; + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->visitProfile(new VisitProfile(ProfileId::fromString('2'))), + ) + ->then( + new ProfileVisited(ProfileId::fromString('2')), + static function (Profile $profile) use (&$called): void { + self::assertSame('1', $profile->id()->toString()); + $called = true; + }, + ); + + $test->assert(); + self::assertTrue($called); + self::assertSame(3, $test::getCount()); + } + + public function testThenWithCallbackMixedBetweenEvents(): void + { + $test = $this->getTester(); + $called = false; + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->visitProfile(new VisitProfile(ProfileId::fromString('2'))), + ) + ->then( + static function (Profile $profile) use (&$called): void { + self::assertSame('1', $profile->id()->toString()); + $called = true; + }, + new ProfileVisited(ProfileId::fromString('2')), + ); + + $test->assert(); + self::assertTrue($called); + self::assertSame(3, $test::getCount()); + } + + public function testThenWithMultipleCallbacks(): void + { + $test = $this->getTester(); + $callbackCallCount = 0; + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->visitProfile(new VisitProfile(ProfileId::fromString('2'))), + ) + ->then( + new ProfileVisited(ProfileId::fromString('2')), + static function () use (&$callbackCallCount): void { + $callbackCallCount++; + }, + static function () use (&$callbackCallCount): void { + $callbackCallCount++; + }, + ); + + $test->assert(); + self::assertSame(2, $callbackCallCount); + self::assertSame(2, $test::getCount()); + } + + public function testThenWithCallbackOnCreation(): void + { + $test = $this->getTester(); + $called = false; + + $test + ->when( + static fn () => Profile::createProfile(new CreateProfile(ProfileId::fromString('1'), Email::fromString('hq@patchlevel.de'))), + ) + ->then( + new ProfileCreated(ProfileId::fromString('1'), Email::fromString('hq@patchlevel.de')), + static function (Profile $profile) use (&$called): void { + self::assertSame('1', $profile->id()->toString()); + $called = true; + }, + ); + + $test->assert(); + self::assertTrue($called); + self::assertSame(3, $test::getCount()); + } + + public function testThenWithOnlyCallbacks(): void + { + $test = $this->getTester(); + $called = false; + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->emitsNoEvents(), + ) + ->then( + static function (Profile $profile) use (&$called): void { + self::assertSame('1', $profile->id()->toString()); + $called = true; + }, + ); + + $test->assert(); + self::assertTrue($called); + self::assertSame(3, $test::getCount()); + } + /** @return Generator, array, array}> */ public static function provideVariousTestCases(): iterable { From 2e0fe835a964420267015e50120c94e0a1a04ceb Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Mon, 16 Feb 2026 10:55:08 +0100 Subject: [PATCH 3/7] docs: add then() closure callbacks section to README --- README.md | 75 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index fa93978..7272a31 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ When this is done, you already can start testing your behaviour. For example tes ```php final class ProfileTest extends AggregateRootTestCase -{ +{ // protected function aggregateClass(): string; - + public function testBehaviour(): void { $this @@ -55,9 +55,9 @@ You can also provide multiple given events and expect multiple events: ```php final class ProfileTest extends AggregateRootTestCase -{ +{ // protected function aggregateClass(): string; - + public function testBehaviour(): void { $this @@ -86,9 +86,9 @@ You can also test the creation of the aggregate: ```php final class ProfileTest extends AggregateRootTestCase -{ +{ // protected function aggregateClass(): string; - + public function testBehaviour(): void { $this @@ -102,9 +102,9 @@ And expect an exception and the message of it: ```php final class ProfileTest extends AggregateRootTestCase -{ +{ // protected function aggregateClass(): string; - + public function testBehaviour(): void { $this @@ -121,6 +121,39 @@ final class ProfileTest extends AggregateRootTestCase } ``` +### Asserting aggregate state + +You can pass closures to `then()` to assert on the aggregate's state after the events have been applied. This is useful +when your aggregate exposes state via public properties or getters that are set in `apply` methods. Closures receive the +aggregate instance and are executed after the event assertion. You can mix closures and expected events freely — event +order is preserved regardless of callback placement. + +```php +final class ProfileTest extends AggregateRootTestCase +{ + // protected function aggregateClass(): string; + + public function testBehaviour(): void + { + $this + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when(static fn (Profile $profile) => $profile->visitProfile(ProfileId::fromString('2'))) + ->then( + new ProfileVisited(ProfileId::fromString('2')), + static fn (Profile $profile) => self::assertSame('1', $profile->id()->toString()), + ); + } +} +``` + +> [!NOTE] +> When `then()` receives only closures and no event objects, it strictly asserts that zero events were emitted. + ### Using Commandbus like syntax When using the command bus and the `#[Handle]` attributes in your aggregate you can also provide the command directly @@ -128,9 +161,9 @@ for the `when` method. ```php final class ProfileTest extends AggregateRootTestCase -{ +{ // protected function aggregateClass(): string; - + public function testBehaviour(): void { $this @@ -145,9 +178,9 @@ example the we need a string which will be directly passed to the event. ```php final class ProfileTest extends AggregateRootTestCase -{ +{ // protected function aggregateClass(): string; - + public function testBehaviour(): void { $this @@ -213,10 +246,10 @@ final class ProfileSubscriberTest extends TestCase { use SubscriberUtilities; - public function testProfileCreated(): void + public function testProfileCreated(): void { $subscriber = new ProfileSubscriber(/* inject deps, if needed */); - + $util = new SubscriberUtilities($subscriber); $util->executeSetup(); $util->executeRun( @@ -226,15 +259,15 @@ final class ProfileSubscriberTest extends TestCase ) ); $util->executeTeardown(); - + self::assertSame(3, $subscriber->count); } } ``` -This Util class can be used for integration or unit tests. +This Util class can be used for integration or unit tests. -You can also pass `Message` instances with additional headers to the `executeRun` method. This allows testing +You can also pass `Message` instances with additional headers to the `executeRun` method. This allows testing subscribers that rely on additional parameters like header information: @@ -267,10 +300,10 @@ final class ProfileSubscriberTest extends TestCase { use SubscriberUtilities; - public function testProfileCreated(): void + public function testProfileCreated(): void { /* Setup and Teardown as before */ - + $util->executeRun( Message::createWithHeaders( new ProfileCreated( @@ -280,8 +313,8 @@ final class ProfileSubscriberTest extends TestCase [new RecordedOnHeader(new DateTimeImmutable('now'))], ) ); - + /* Your assertions */ } } -``` \ No newline at end of file +``` From 4c64e7cdad7716578802fe1ca45d1cc597a0903b Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Mon, 16 Feb 2026 11:38:30 +0100 Subject: [PATCH 4/7] refactor: wrap then() callback invocation with TypeError catch for better DX When a then() callback has an incompatible type hint, the TypeError now includes the callback's file and line number, making it much easier to locate the offending closure. --- src/Test/AggregateRootTestCase.php | 19 +++++++++++++- tests/Unit/Test/AggregateRootTestCaseTest.php | 25 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Test/AggregateRootTestCase.php b/src/Test/AggregateRootTestCase.php index c8e6059..0eb2402 100644 --- a/src/Test/AggregateRootTestCase.php +++ b/src/Test/AggregateRootTestCase.php @@ -13,10 +13,13 @@ use PHPUnit\Framework\Constraint\ExceptionMessageIsOrContains; use PHPUnit\Framework\TestCase; use ReflectionClass; +use ReflectionFunction; use Throwable; +use TypeError; use function array_filter; use function array_values; +use function sprintf; abstract class AggregateRootTestCase extends TestCase { @@ -143,7 +146,21 @@ final public function assert(): self self::assertEquals($expectedEvents, $events, 'The events doesn\'t match the expected events.'); foreach ($expectationCallbacks as $callback) { - $callback($aggregate); + try { + $callback($aggregate); + } catch (TypeError $e) { + $reflection = new ReflectionFunction($callback); + + throw new TypeError( + sprintf( + 'Invalid then() callback defined in %s on line %d: %s', + $reflection->getFileName(), + $reflection->getStartLine(), + $e->getMessage(), + ), + previous: $e, + ); + } } return $this; diff --git a/tests/Unit/Test/AggregateRootTestCaseTest.php b/tests/Unit/Test/AggregateRootTestCaseTest.php index 9d4b486..fc92649 100644 --- a/tests/Unit/Test/AggregateRootTestCaseTest.php +++ b/tests/Unit/Test/AggregateRootTestCaseTest.php @@ -22,6 +22,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; +use TypeError; #[CoversClass(AggregateRootTestCase::class)] final class AggregateRootTestCaseTest extends TestCase @@ -484,6 +485,30 @@ static function (Profile $profile) use (&$called): void { self::assertSame(3, $test::getCount()); } + public function testThenWithIncompatibleCallback(): void + { + $test = $this->getTester(); + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->emitsNoEvents(), + ) + ->then( + static function (string $incompatible): void { + }, + ); + + $this->expectException(TypeError::class); + $this->expectExceptionMessageMatches('/Invalid then\(\) callback defined in/'); + $test->assert(); + } + /** @return Generator, array, array}> */ public static function provideVariousTestCases(): iterable { From 2b3da35bf3750d9f747fe027ed4a32b2f0d11f4c Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Mon, 16 Feb 2026 16:33:26 +0100 Subject: [PATCH 5/7] refactor: catch all Throwables in then() callbacks and cause test failure Widen the catch block from TypeError to Throwable so any error in a then() callback produces a clear test failure with file/line context. PHPUnit assertion failures are rethrown directly to preserve their original message. --- src/Test/AggregateRootTestCase.php | 41 ++++++------------- tests/Unit/Test/AggregateRootTestCaseTest.php | 6 +-- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/Test/AggregateRootTestCase.php b/src/Test/AggregateRootTestCase.php index 0eb2402..90b5bd0 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; @@ -15,7 +16,6 @@ use ReflectionClass; use ReflectionFunction; use Throwable; -use TypeError; use function array_filter; use function array_values; @@ -33,7 +33,7 @@ abstract class AggregateRootTestCase extends TestCase /** @var array */ private array $thenExpectations = []; - /** @var class-string|null */ + /** @var class-string|null */ private string|null $expectedException = null; private string|null $expectedExceptionMessage = null; @@ -111,13 +111,7 @@ final public function assert(): self $reflection = new ReflectionClass($this->aggregateClass()); $reflectionMethod = $reflection->getMethod($handler->method); - $return = $reflectionMethod->invokeArgs( - $handler->static ? null : $aggregate, - [ - $callableOrCommand, - ...$this->parameters, - ], - ); + $return = $reflectionMethod->invokeArgs($handler->static ? null : $aggregate, [$callableOrCommand, ...$this->parameters,]); } } @@ -138,8 +132,8 @@ final public function assert(): self throw new NoAggregateCreated(); } - $expectedEvents = array_values(array_filter($this->thenExpectations, static fn (object $item) => !$item instanceof Closure)); - $expectationCallbacks = array_filter($this->thenExpectations, static fn (object $item) => $item instanceof Closure); + $expectedEvents = array_values(array_filter($this->thenExpectations, static fn(object $item) => !$item instanceof Closure)); + $expectationCallbacks = array_filter($this->thenExpectations, static fn(object $item) => $item instanceof Closure); $events = $aggregate->releaseEvents(); @@ -148,17 +142,18 @@ final public function assert(): self foreach ($expectationCallbacks as $callback) { try { $callback($aggregate); - } catch (TypeError $e) { + } catch (AssertionFailedError $e) { + throw $e; + } catch (Throwable $t) { $reflection = new ReflectionFunction($callback); - throw new TypeError( + self::fail( sprintf( - 'Invalid then() callback defined in %s on line %d: %s', + 'then() callback defined in %s on line %d failed: %s', $reflection->getFileName(), $reflection->getStartLine(), - $e->getMessage(), + $t->getMessage(), ), - previous: $e, ); } } @@ -182,22 +177,12 @@ private function handleException(Throwable $throwable): void $checked = false; if ($this->expectedException) { - self::assertThat( - $throwable, - new ExceptionConstraint( - $this->expectedException, - ), - ); + self::assertThat($throwable, new ExceptionConstraint($this->expectedException,)); $checked = true; } if ($this->expectedExceptionMessage) { - self::assertThat( - $throwable->getMessage(), - new ExceptionMessageIsOrContains( - $this->expectedExceptionMessage, - ), - ); + self::assertThat($throwable->getMessage(), new ExceptionMessageIsOrContains($this->expectedExceptionMessage,)); $checked = true; } diff --git a/tests/Unit/Test/AggregateRootTestCaseTest.php b/tests/Unit/Test/AggregateRootTestCaseTest.php index fc92649..29fc7c5 100644 --- a/tests/Unit/Test/AggregateRootTestCaseTest.php +++ b/tests/Unit/Test/AggregateRootTestCaseTest.php @@ -19,10 +19,10 @@ use Patchlevel\EventSourcing\PhpUnit\Tests\Unit\Fixture\ProfileId; use Patchlevel\EventSourcing\PhpUnit\Tests\Unit\Fixture\ProfileVisited; use Patchlevel\EventSourcing\PhpUnit\Tests\Unit\Fixture\VisitProfile; +use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use TypeError; #[CoversClass(AggregateRootTestCase::class)] final class AggregateRootTestCaseTest extends TestCase @@ -504,8 +504,8 @@ static function (string $incompatible): void { }, ); - $this->expectException(TypeError::class); - $this->expectExceptionMessageMatches('/Invalid then\(\) callback defined in/'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessageMatches('/then\(\) callback defined in .+ failed:/'); $test->assert(); } From 18401f7368e3d7111a9394e47952db1790926192 Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Mon, 16 Feb 2026 22:35:02 +0100 Subject: [PATCH 6/7] test: catch all Throwables in then() callbacks and cause test failure --- tests/Unit/Test/AggregateRootTestCaseTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/Unit/Test/AggregateRootTestCaseTest.php b/tests/Unit/Test/AggregateRootTestCaseTest.php index 29fc7c5..1b014a5 100644 --- a/tests/Unit/Test/AggregateRootTestCaseTest.php +++ b/tests/Unit/Test/AggregateRootTestCaseTest.php @@ -485,6 +485,31 @@ static function (Profile $profile) use (&$called): void { self::assertSame(3, $test::getCount()); } + public function testThenWithFailingAssertionInCallbackRethrowsOriginalError(): void + { + $test = $this->getTester(); + + $test + ->given( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hq@patchlevel.de'), + ), + ) + ->when( + static fn (Profile $profile) => $profile->emitsNoEvents(), + ) + ->then( + static function (Profile $profile): void { + self::assertSame('unexpected-id', $profile->id()->toString(), 'Expected fail!'); + }, + ); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Expected fail!'); + $test->assert(); + } + public function testThenWithIncompatibleCallback(): void { $test = $this->getTester(); From 0f308ce4eaf451c66328c46def616592943c4fd1 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Tue, 17 Feb 2026 12:43:42 +0100 Subject: [PATCH 7/7] Fix CS and remove unneeded AssertionFailed catch --- src/Test/AggregateRootTestCase.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Test/AggregateRootTestCase.php b/src/Test/AggregateRootTestCase.php index 90b5bd0..a76e1a0 100644 --- a/src/Test/AggregateRootTestCase.php +++ b/src/Test/AggregateRootTestCase.php @@ -7,7 +7,6 @@ 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; @@ -111,7 +110,7 @@ final public function assert(): self $reflection = new ReflectionClass($this->aggregateClass()); $reflectionMethod = $reflection->getMethod($handler->method); - $return = $reflectionMethod->invokeArgs($handler->static ? null : $aggregate, [$callableOrCommand, ...$this->parameters,]); + $return = $reflectionMethod->invokeArgs($handler->static ? null : $aggregate, [$callableOrCommand, ...$this->parameters]); } } @@ -132,8 +131,8 @@ final public function assert(): self throw new NoAggregateCreated(); } - $expectedEvents = array_values(array_filter($this->thenExpectations, static fn(object $item) => !$item instanceof Closure)); - $expectationCallbacks = array_filter($this->thenExpectations, static fn(object $item) => $item instanceof Closure); + $expectedEvents = array_values(array_filter($this->thenExpectations, static fn (object $item) => !$item instanceof Closure)); + $expectationCallbacks = array_filter($this->thenExpectations, static fn (object $item) => $item instanceof Closure); $events = $aggregate->releaseEvents(); @@ -142,8 +141,6 @@ final public function assert(): self foreach ($expectationCallbacks as $callback) { try { $callback($aggregate); - } catch (AssertionFailedError $e) { - throw $e; } catch (Throwable $t) { $reflection = new ReflectionFunction($callback); @@ -177,12 +174,12 @@ private function handleException(Throwable $throwable): void $checked = false; if ($this->expectedException) { - self::assertThat($throwable, new ExceptionConstraint($this->expectedException,)); + self::assertThat($throwable, new ExceptionConstraint($this->expectedException)); $checked = true; } if ($this->expectedExceptionMessage) { - self::assertThat($throwable->getMessage(), new ExceptionMessageIsOrContains($this->expectedExceptionMessage,)); + self::assertThat($throwable->getMessage(), new ExceptionMessageIsOrContains($this->expectedExceptionMessage)); $checked = true; }