From 30c6b31d597d8abba2462f4e7ee44927d0d626e7 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Sat, 6 Sep 2025 17:41:26 +0200 Subject: [PATCH 1/2] Use native feature of infection to include SA tooling. Dropping roave/infection-static-analysis-plugin in favor of the native option infection is offering now. This also means switching from psalm to phpstan as the SA tool used with infection. Switch from `--only-covered` to `--with-uncovered` as the first option does not exist anymore --- .github/workflows/mutation-tests-diff.yml | 2 +- .github/workflows/mutation-tests.yml | 2 +- composer.json | 3 +- composer.lock | 238 +++++++++++++++++----- 4 files changed, 189 insertions(+), 56 deletions(-) diff --git a/.github/workflows/mutation-tests-diff.yml b/.github/workflows/mutation-tests-diff.yml index 452fd2e..a06ff70 100644 --- a/.github/workflows/mutation-tests-diff.yml +++ b/.github/workflows/mutation-tests-diff.yml @@ -39,4 +39,4 @@ jobs: dependency-versions: ${{ matrix.dependencies }} - name: "Infection" - run: "vendor/bin/roave-infection-static-analysis-plugin --threads=max --git-diff-lines --git-diff-base=origin/$GITHUB_BASE_REF --ignore-msi-with-no-mutations --only-covered --min-msi=90 --min-covered-msi=95" + run: "vendor/bin/infection --threads=max --static-analysis-tool=phpstan --git-diff-lines --git-diff-base=origin/$GITHUB_BASE_REF --ignore-msi-with-no-mutations --with-uncovered --min-msi=90 --min-covered-msi=95" diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml index 4d85bd3..28863f8 100644 --- a/.github/workflows/mutation-tests.yml +++ b/.github/workflows/mutation-tests.yml @@ -41,6 +41,6 @@ jobs: dependency-versions: ${{ matrix.dependencies }} - name: "Infection" - run: "vendor/bin/roave-infection-static-analysis-plugin --threads=max" + run: "vendor/bin/infection --threads=max --static-analysis-tool=phpstan" env: STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} diff --git a/composer.json b/composer.json index c26a2de..dcad0e5 100644 --- a/composer.json +++ b/composer.json @@ -27,13 +27,12 @@ "symfony/type-info": "^7.3.0" }, "require-dev": { - "infection/infection": "^0.29.10", + "infection/infection": "^0.31.9", "patchlevel/coding-standard": "^1.3.0", "phpbench/phpbench": "^1.2.15", "phpstan/phpstan": "^2.1.0", "phpunit/phpunit": "^11.5.17", "psalm/plugin-phpunit": "^0.19.2", - "roave/infection-static-analysis-plugin": "^1.36.0", "symfony/var-dumper": "^5.4.29 || ^6.4.0 || ^7.0.0", "vimeo/psalm": "^6.0.0" }, diff --git a/composer.lock b/composer.lock index 2bc0722..e871047 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fed5b49085b4a2388a7e726d2e6e2f65", + "content-hash": "1cbecd86ae94f4ff685bfa4ae3240be7", "packages": [ { "name": "psr/cache", @@ -2366,38 +2366,40 @@ }, { "name": "infection/infection", - "version": "0.29.14", + "version": "0.31.9", "source": { "type": "git", "url": "https://github.com/infection/infection.git", - "reference": "feea2a48a8aeedd3a4d2105167b41a46f0e568a3" + "reference": "f9628fcd7f76eadf24726e57a81937c42458232b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/infection/zipball/feea2a48a8aeedd3a4d2105167b41a46f0e568a3", - "reference": "feea2a48a8aeedd3a4d2105167b41a46f0e568a3", + "url": "https://api.github.com/repos/infection/infection/zipball/f9628fcd7f76eadf24726e57a81937c42458232b", + "reference": "f9628fcd7f76eadf24726e57a81937c42458232b", "shasum": "" }, "require": { - "colinodell/json5": "^2.2 || ^3.0", + "colinodell/json5": "^3.0", "composer-runtime-api": "^2.0", - "composer/xdebug-handler": "^2.0 || ^3.0", + "composer/xdebug-handler": "^3.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", - "fidry/cpu-core-counter": "^0.4.0 || ^0.5.0 || ^1.0", + "fidry/cpu-core-counter": "^1.0", "infection/abstract-testframework-adapter": "^0.5.0", "infection/extension-installer": "^0.1.0", "infection/include-interceptor": "^0.2.5", "infection/mutator": "^0.4", - "justinrainbow/json-schema": "^5.3 || ^6.0", + "justinrainbow/json-schema": "^6.0", "nikic/php-parser": "^5.3", "ondram/ci-detector": "^4.1.0", "php": "^8.2", - "sanmai/later": "^0.1.1", - "sanmai/pipeline": "^5.1 || ^6", - "sebastian/diff": "^3.0.2 || ^4.0 || ^5.0 || ^6.0 || ^7.0", + "sanmai/di-container": "^0.1.4", + "sanmai/duoclock": "^0.1.0", + "sanmai/later": "^0.1.7", + "sanmai/pipeline": "^7.0", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0", "symfony/console": "^6.4 || ^7.0", "symfony/filesystem": "^6.4 || ^7.0", "symfony/finder": "^6.4 || ^7.0", @@ -2407,8 +2409,7 @@ }, "conflict": { "antecedent/patchwork": "<2.1.25", - "dg/bypass-finals": "<1.4.1", - "phpunit/php-code-coverage": ">9,<9.1.4 || >9.2.17,<9.2.21" + "dg/bypass-finals": "<1.4.1" }, "require-dev": { "ext-simplexml": "*", @@ -2418,8 +2419,10 @@ "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", "phpstan/phpstan-webmozart-assert": "^2.0", - "phpunit/phpunit": "^11.5", + "phpunit/phpunit": "^11.5.27", "rector/rector": "^2.0", + "shipmonk/dead-code-detector": "^0.12.0", + "shipmonk/name-collision-detector": "^2.1", "sidz/phpstan-rules": "^0.5.1", "symfony/yaml": "^6.4 || ^7.0", "thecodingmachine/phpstan-safe-rule": "^1.4" @@ -2478,7 +2481,7 @@ ], "support": { "issues": "https://github.com/infection/infection/issues", - "source": "https://github.com/infection/infection/tree/0.29.14" + "source": "https://github.com/infection/infection/tree/0.31.9" }, "funding": [ { @@ -2490,7 +2493,7 @@ "type": "open_collective" } ], - "time": "2025-03-02T18:49:12+00:00" + "time": "2025-10-27T12:00:54+00:00" }, { "name": "infection/mutator", @@ -4279,6 +4282,54 @@ }, "time": "2025-03-31T18:49:55+00:00" }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, { "name": "psr/http-factory", "version": "1.1.0", @@ -4510,60 +4561,143 @@ "time": "2025-01-25T19:27:39+00:00" }, { - "name": "roave/infection-static-analysis-plugin", - "version": "1.39.0", + "name": "sanmai/di-container", + "version": "0.1.5", "source": { "type": "git", - "url": "https://github.com/Roave/infection-static-analysis-plugin.git", - "reference": "8f4b2c20f55c51d6d1af53daccc5ee03bf2198de" + "url": "https://github.com/sanmai/di-container.git", + "reference": "355534ad7970fc7dab4211ecaf2da5c546855ee8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/infection-static-analysis-plugin/zipball/8f4b2c20f55c51d6d1af53daccc5ee03bf2198de", - "reference": "8f4b2c20f55c51d6d1af53daccc5ee03bf2198de", + "url": "https://api.github.com/repos/sanmai/di-container/zipball/355534ad7970fc7dab4211ecaf2da5c546855ee8", + "reference": "355534ad7970fc7dab4211ecaf2da5c546855ee8", "shasum": "" }, "require": { - "composer-runtime-api": "^2.2", - "infection/infection": "0.29.14", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "sanmai/later": "^0.1.7", - "vimeo/psalm": "^6.13.1" - }, - "conflict": { - "symfony/polyfill-php84": "<1.30.0" + "php": ">=8.2", + "psr/container": "^1.1.2 || ^2.0", + "sanmai/pipeline": "^6.17 || ^7.0" }, "require-dev": { - "azjezz/psl": "^3.3.0", - "doctrine/coding-standard": "^13.0.1", - "phpunit/phpunit": "^11.5.34", - "psalm/plugin-phpunit": "^0.19.5" + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^3.17", + "infection/infection": ">=0.29", + "php-coveralls/php-coveralls": "^2.4.1", + "phpstan/extension-installer": "^1.4", + "phpunit/phpunit": "^11.5.25", + "sanmai/phpstan-rules": "^0.3.10" }, - "bin": [ - "bin/roave-infection-static-analysis-plugin" + "type": "library", + "extra": { + "preferred-install": "dist" + }, + "autoload": { + "psr-4": { + "DIContainer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "homepage": "https://github.com/sanmai" + }, + { + "name": "Maks Rafalko", + "homepage": "https://twitter.com/maks_rafalko" + }, + { + "name": "Théo FIDRY", + "homepage": "https://twitter.com/tfidry" + } + ], + "description": "dependency injection container with automatic constructor dependency resolution", + "keywords": [ + "Autowiring", + "constructor di", + "di container", + "psr 11" + ], + "support": { + "issues": "https://github.com/sanmai/di-container/issues", + "source": "https://github.com/sanmai/di-container/tree/0.1.5" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2025-08-04T09:43:58+00:00" + }, + { + "name": "sanmai/duoclock", + "version": "0.1.1", + "source": { + "type": "git", + "url": "https://github.com/sanmai/DuoClock.git", + "reference": "30aa40092396dc96b68c8e8d49162619574477e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/DuoClock/zipball/30aa40092396dc96b68c8e8d49162619574477e2", + "reference": "30aa40092396dc96b68c8e8d49162619574477e2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^3.17", + "infection/infection": ">=0.29", + "php-coveralls/php-coveralls": "^2.4.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^11.5.25", + "sanmai/phpstan-rules": "^0.3.1", + "vimeo/psalm": "^6.12" + }, "type": "library", + "extra": { + "preferred-install": "dist" + }, "autoload": { "psr-4": { - "Roave\\InfectionStaticAnalysis\\": "src/Roave/InfectionStaticAnalysis" + "DuoClock\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" } ], - "description": "Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis", + "description": "PHP time mocking for tests - PSR-20 clock with mockable sleep(), time(), and TimeSpy for PHPUnit testing", "support": { - "issues": "https://github.com/Roave/infection-static-analysis-plugin/issues", - "source": "https://github.com/Roave/infection-static-analysis-plugin/tree/1.39.0" + "issues": "https://github.com/sanmai/DuoClock/issues", + "source": "https://github.com/sanmai/DuoClock/tree/0.1.1" }, - "time": "2025-08-21T11:27:22+00:00" + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2025-07-28T02:17:28+00:00" }, { "name": "sanmai/later", @@ -4631,16 +4765,16 @@ }, { "name": "sanmai/pipeline", - "version": "6.22", + "version": "7.5", "source": { "type": "git", "url": "https://github.com/sanmai/pipeline.git", - "reference": "fb8d0c23b4ef085315a36d397fafa052203020ce" + "reference": "c3b87db671ee0bc286860bd13bdb7cfc108b7d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/pipeline/zipball/fb8d0c23b4ef085315a36d397fafa052203020ce", - "reference": "fb8d0c23b4ef085315a36d397fafa052203020ce", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/c3b87db671ee0bc286860bd13bdb7cfc108b7d7e", + "reference": "c3b87db671ee0bc286860bd13bdb7cfc108b7d7e", "shasum": "" }, "require": { @@ -4656,7 +4790,7 @@ "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2", "phpunit/phpunit": ">=9.4 <12", - "sanmai/phpstan-rules": "^0.3.0", + "sanmai/phpstan-rules": "^0.3.11", "sanmai/phpunit-double-colon-syntax": "^0.1.1", "vimeo/psalm": ">=2" }, @@ -4687,7 +4821,7 @@ "description": "General-purpose collections pipeline", "support": { "issues": "https://github.com/sanmai/pipeline/issues", - "source": "https://github.com/sanmai/pipeline/tree/6.22" + "source": "https://github.com/sanmai/pipeline/tree/7.5" }, "funding": [ { @@ -4695,7 +4829,7 @@ "type": "github" } ], - "time": "2025-07-22T09:07:07+00:00" + "time": "2025-11-05T10:54:07+00:00" }, { "name": "sebastian/cli-parser", From a3fea5945834af64a9177fa81681554871c40ad9 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Wed, 19 Nov 2025 17:32:52 +0100 Subject: [PATCH 2/2] Lower msi a bit, add some exception code checks --- infection.json.dist | 2 +- tests/Unit/MetadataHydratorTest.php | 1 + tests/Unit/Normalizer/ArrayNormalizerTest.php | 2 ++ tests/Unit/Normalizer/ArrayShapeNormalizerTest.php | 2 ++ tests/Unit/Normalizer/DateTimeImmutableNormalizerTest.php | 2 ++ tests/Unit/Normalizer/DateTimeNormalizerTest.php | 2 ++ tests/Unit/Normalizer/DateTimeZoneNormalizerTest.php | 2 ++ tests/Unit/Normalizer/EnumNormalizerTest.php | 2 ++ tests/Unit/Normalizer/ObjectNormalizerTest.php | 2 ++ 9 files changed, 16 insertions(+), 1 deletion(-) diff --git a/infection.json.dist b/infection.json.dist index ba1df74..ff79d4d 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -15,6 +15,6 @@ "@default": true }, "minMsi": 84, - "minCoveredMsi": 92, + "minCoveredMsi": 88, "testFrameworkOptions": "--testsuite=unit" } diff --git a/tests/Unit/MetadataHydratorTest.php b/tests/Unit/MetadataHydratorTest.php index c5efaa9..14a6cb7 100644 --- a/tests/Unit/MetadataHydratorTest.php +++ b/tests/Unit/MetadataHydratorTest.php @@ -173,6 +173,7 @@ public function testHydrate(): void public function testHydrateUnknownClass(): void { $this->expectException(ClassNotSupported::class); + $this->expectExceptionCode(0); $this->hydrator->hydrate( 'Unknown', diff --git a/tests/Unit/Normalizer/ArrayNormalizerTest.php b/tests/Unit/Normalizer/ArrayNormalizerTest.php index b320b83..fdc8c71 100644 --- a/tests/Unit/Normalizer/ArrayNormalizerTest.php +++ b/tests/Unit/Normalizer/ArrayNormalizerTest.php @@ -34,6 +34,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $innerNormalizer = $this->createMock(Normalizer::class); @@ -44,6 +45,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $innerNormalizer = $this->createMock(Normalizer::class); diff --git a/tests/Unit/Normalizer/ArrayShapeNormalizerTest.php b/tests/Unit/Normalizer/ArrayShapeNormalizerTest.php index 79dc159..45fdfcc 100644 --- a/tests/Unit/Normalizer/ArrayShapeNormalizerTest.php +++ b/tests/Unit/Normalizer/ArrayShapeNormalizerTest.php @@ -34,6 +34,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $innerNormalizer = $this->createMock(Normalizer::class); @@ -44,6 +45,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $innerNormalizer = $this->createMock(Normalizer::class); diff --git a/tests/Unit/Normalizer/DateTimeImmutableNormalizerTest.php b/tests/Unit/Normalizer/DateTimeImmutableNormalizerTest.php index fb90e0f..7a4c22b 100644 --- a/tests/Unit/Normalizer/DateTimeImmutableNormalizerTest.php +++ b/tests/Unit/Normalizer/DateTimeImmutableNormalizerTest.php @@ -29,6 +29,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $normalizer = new DateTimeImmutableNormalizer(); $normalizer->normalize(123); @@ -37,6 +38,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $normalizer = new DateTimeImmutableNormalizer(); $normalizer->denormalize(123); diff --git a/tests/Unit/Normalizer/DateTimeNormalizerTest.php b/tests/Unit/Normalizer/DateTimeNormalizerTest.php index 0588ef0..d585727 100644 --- a/tests/Unit/Normalizer/DateTimeNormalizerTest.php +++ b/tests/Unit/Normalizer/DateTimeNormalizerTest.php @@ -28,6 +28,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $normalizer = new DateTimeNormalizer(); $normalizer->normalize(123); @@ -36,6 +37,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $normalizer = new DateTimeNormalizer(); $normalizer->denormalize(123); diff --git a/tests/Unit/Normalizer/DateTimeZoneNormalizerTest.php b/tests/Unit/Normalizer/DateTimeZoneNormalizerTest.php index 0af3a8b..f0300b3 100644 --- a/tests/Unit/Normalizer/DateTimeZoneNormalizerTest.php +++ b/tests/Unit/Normalizer/DateTimeZoneNormalizerTest.php @@ -28,6 +28,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $normalizer = new DateTimeZoneNormalizer(); $normalizer->normalize(123); @@ -36,6 +37,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $normalizer = new DateTimeZoneNormalizer(); $normalizer->denormalize(123); diff --git a/tests/Unit/Normalizer/EnumNormalizerTest.php b/tests/Unit/Normalizer/EnumNormalizerTest.php index 4ac8dd7..dcaf1b5 100644 --- a/tests/Unit/Normalizer/EnumNormalizerTest.php +++ b/tests/Unit/Normalizer/EnumNormalizerTest.php @@ -34,6 +34,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $this->expectExceptionMessage('type "Patchlevel\Hydrator\Tests\Unit\Fixture\Status|null" was expected but "string" was passed.'); $normalizer = new EnumNormalizer(Status::class); @@ -43,6 +44,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $this->expectExceptionMessage('foo'); $this->expectExceptionMessage('Patchlevel\Hydrator\Tests\Unit\Fixture\Status'); diff --git a/tests/Unit/Normalizer/ObjectNormalizerTest.php b/tests/Unit/Normalizer/ObjectNormalizerTest.php index 485aaa1..3b894e1 100644 --- a/tests/Unit/Normalizer/ObjectNormalizerTest.php +++ b/tests/Unit/Normalizer/ObjectNormalizerTest.php @@ -65,6 +65,7 @@ public function testDenormalizeWithNull(): void public function testNormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $this->expectExceptionMessage('type "Patchlevel\Hydrator\Tests\Unit\Fixture\ProfileCreated|null" was expected but "string" was passed.'); $hydrator = $this->createMock(Hydrator::class); @@ -77,6 +78,7 @@ public function testNormalizeWithInvalidArgument(): void public function testDenormalizeWithInvalidArgument(): void { $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); $this->expectExceptionMessage('array|null" was expected but "string" was passed.'); $hydrator = $this->createMock(Hydrator::class);