chore: upgrade phpunit to 12.5

This commit is contained in:
fromme committed 2026-10-01 10:07:05 +02:00
1 parent da039d0527
commit 849da8d471
53 files changed
+832 -856

No files matched your search

+2 -2
View File
@@ -12,11 +12,11 @@
###> phpunit/phpunit ### ###> phpunit/phpunit ###
/phpunit.xml /phpunit.xml
.phpunit.result.cache /.phpunit.cache/
###< phpunit/phpunit ### ###< phpunit/phpunit ###
###> symfony/phpunit-bridge ### ###> symfony/phpunit-bridge ###
.phpunit.result.cache /.phpunit.cache/
/phpunit.xml /phpunit.xml
###< symfony/phpunit-bridge ### ###< symfony/phpunit-bridge ###
+5 -11
View File
@@ -5,15 +5,9 @@ if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC'); ini_set('date.timezone', 'UTC');
} }
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) { if (!is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php'); echo "Unable to find PHPUnit in `vendor/phpunit/phpunit/`. Run `composer install`.\n";
require PHPUNIT_COMPOSER_INSTALL; exit(1);
PHPUnit\TextUI\Command::main();
} else {
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
exit(1);
}
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
} }
require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit';
+1 -1
View File
@@ -138,7 +138,7 @@
"fakerphp/faker": "*", "fakerphp/faker": "*",
"friendsofphp/php-cs-fixer": "^3.84", "friendsofphp/php-cs-fixer": "^3.84",
"marcocesarato/php-conventional-changelog": "^1.17", "marcocesarato/php-conventional-changelog": "^1.17",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^12.5",
"rector/rector": "^2.6", "rector/rector": "^2.6",
"symfony/browser-kit": "7.4.*", "symfony/browser-kit": "7.4.*",
"symfony/css-selector": "7.4.*", "symfony/css-selector": "7.4.*",
Generated
+606 -623
View File
File diff suppressed because it is too large. Load diff
+18 -10
View File
@@ -1,20 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html --> <!-- https://docs.phpunit.de/en/12.5/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false" backupGlobals="false"
colors="true" colors="true"
bootstrap="tests/bootstrap.php" bootstrap="tests/bootstrap.php"
convertDeprecationsToExceptions="false" cacheDirectory=".phpunit.cache"
failOnDeprecation="true"
failOnNotice="true"
failOnWarning="true"
displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnTestsThatTriggerNotices="true"
displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnPhpunitDeprecations="true"
displayDetailsOnPhpunitNotices="true"
> >
<php> <php>
<ini name="display_errors" value="1" /> <ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" /> <ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" /> <server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" /> <server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
</php> </php>
<testsuites> <testsuites>
@@ -23,13 +29,15 @@
</testsuite> </testsuite>
</testsuites> </testsuites>
<coverage processUncoveredFiles="true"> <!-- Symfony triggers its deprecations with @trigger_error(); without
ignoreSuppressionOfDeprecations PHPUnit would swallow them all. -->
<source ignoreSuppressionOfDeprecations="true">
<include> <include>
<directory suffix=".php">src</directory> <directory>src</directory>
</include> </include>
</coverage> </source>
<listeners> <extensions>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" /> <bootstrap class="Symfony\Bridge\PhpUnit\SymfonyExtension" />
</listeners> </extensions>
</phpunit> </phpunit>
+6 -11
View File
@@ -15,10 +15,12 @@ use App\Entity\Teamer;
use App\Entity\User; use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
#[AllowMockObjectsWithoutExpectations]
class UserDataHandlerTest extends TestCase class UserDataHandlerTest extends TestCase
{ {
private EntityManagerInterface&MockObject $entityManager; private EntityManagerInterface&MockObject $entityManager;
@@ -30,9 +32,7 @@ class UserDataHandlerTest extends TestCase
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('collectRolesProvider')]
* @dataProvider collectRolesProvider
*/
public function testCollectRolesImportsAdministrativeRolesAsPendingOnly(CrmAttributesResponse $crmAttributes, array $expectedRoles): void public function testCollectRolesImportsAdministrativeRolesAsPendingOnly(CrmAttributesResponse $crmAttributes, array $expectedRoles): void
{ {
$handler = new UserDataHandler($this->entityManager, $this->logger); $handler = new UserDataHandler($this->entityManager, $this->logger);
@@ -86,9 +86,8 @@ class UserDataHandlerTest extends TestCase
/** /**
* The role policy has to be identical whichever identity source claims the role, so * The role policy has to be identical whichever identity source claims the role, so
* toPendingRoles() must agree with collectPendingRoles() on equivalent input. * toPendingRoles() must agree with collectPendingRoles() on equivalent input.
*
* @dataProvider toPendingRolesProvider
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('toPendingRolesProvider')]
public function testToPendingRolesMatchesTheCrmPolicy(array $claimedRoles, CrmAttributesResponse $crmAttributes, array $expectedRoles): void public function testToPendingRolesMatchesTheCrmPolicy(array $claimedRoles, CrmAttributesResponse $crmAttributes, array $expectedRoles): void
{ {
$handler = new UserDataHandler($this->entityManager, $this->logger); $handler = new UserDataHandler($this->entityManager, $this->logger);
@@ -231,9 +230,7 @@ class UserDataHandlerTest extends TestCase
$this->assertSame('[email protected]', $teamer->getCommunication()?->getEmail()); $this->assertSame('[email protected]', $teamer->getCommunication()?->getEmail());
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('pendingRolesProvider')]
* @dataProvider pendingRolesProvider
*/
public function testUpdateLocalUserRefreshesThePendingRoles( public function testUpdateLocalUserRefreshesThePendingRoles(
array $roles, array $roles,
array $claimedRoles, array $claimedRoles,
@@ -441,9 +438,7 @@ class UserDataHandlerTest extends TestCase
$this->assertSame([User::PENDING_ROLES['ROLE_HOUSE_MANAGER']], $user->getPendingRoles()); $this->assertSame([User::PENDING_ROLES['ROLE_HOUSE_MANAGER']], $user->getPendingRoles());
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('unapprovableRoleProvider')]
* @dataProvider unapprovableRoleProvider
*/
public function testApproveRoleRefusesARoleWithoutANomination(array $roles, string $role): void public function testApproveRoleRefusesARoleWithoutANomination(array $roles, string $role): void
{ {
$user = (new User()) $user = (new User())
+5 -4
View File
@@ -11,6 +11,7 @@ use App\MyEp\Import\TravelExport;
use App\MyEp\Import\TravelExportClient; use App\MyEp\Import\TravelExportClient;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
@@ -87,7 +88,7 @@ class MyEpImportCommandTest extends TestCase
public function testItRefusesToRunWhenTheExportCannotBeRead(): void public function testItRefusesToRunWhenTheExportCannotBeRead(): void
{ {
$client = $this->createMock(TravelExportClient::class); $client = $this->createStub(TravelExportClient::class);
$client->method('fetchAll')->willThrowException(new ApiException('gateway timeout')); $client->method('fetchAll')->willThrowException(new ApiException('gateway timeout'));
$tester = new CommandTester(new MyEpImportCommand( $tester = new CommandTester(new MyEpImportCommand(
@@ -184,7 +185,7 @@ class MyEpImportCommandTest extends TestCase
int $skipped = 0, int $skipped = 0,
int $pickupsWithoutMasterData = 0, int $pickupsWithoutMasterData = 0,
): CommandTester { ): CommandTester {
$client = $this->createMock(TravelExportClient::class); $client = $this->createStub(TravelExportClient::class);
$client->method('fetchAll')->willReturn( $client->method('fetchAll')->willReturn(
new TravelExport($rows, $skipped, $pickupsWithoutMasterData, '2026-09-29T03:20:00+02:00') new TravelExport($rows, $skipped, $pickupsWithoutMasterData, '2026-09-29T03:20:00+02:00')
); );
@@ -212,9 +213,9 @@ class MyEpImportCommandTest extends TestCase
return $connection; return $connection;
} }
private function writingConnection(int $existingId): Connection&MockObject private function writingConnection(int $existingId): Connection&Stub
{ {
$connection = $this->createMock(Connection::class); $connection = $this->createStub(Connection::class);
$connection->method('fetchOne')->willReturn($existingId); $connection->method('fetchOne')->willReturn($existingId);
return $connection; return $connection;
+4 -12
View File
@@ -14,9 +14,7 @@ class SeasonCalendarTest extends TestCase
return new SeasonCalendar('11-01', '04-01'); return new SeasonCalendar('11-01', '04-01');
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('winterDates')]
* @dataProvider winterDates
*/
public function testSeasonYearForTheWrappingWinterWindow(string $date, ?int $expected): void public function testSeasonYearForTheWrappingWinterWindow(string $date, ?int $expected): void
{ {
$this->assertSame($expected, $this->winter()->seasonYearFor(new \DateTimeImmutable($date))); $this->assertSame($expected, $this->winter()->seasonYearFor(new \DateTimeImmutable($date)));
@@ -44,9 +42,7 @@ class SeasonCalendarTest extends TestCase
$this->assertSame('außerhalb der Saison', $calendar->label(null)); $this->assertSame('außerhalb der Saison', $calendar->label(null));
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('summerDates')]
* @dataProvider summerDates
*/
public function testSeasonYearForANonWrappingWindow(string $date, ?int $expected): void public function testSeasonYearForANonWrappingWindow(string $date, ?int $expected): void
{ {
$calendar = new SeasonCalendar('06-01', '09-01'); $calendar = new SeasonCalendar('06-01', '09-01');
@@ -71,9 +67,7 @@ class SeasonCalendarTest extends TestCase
(new SeasonCalendar('xx-yy', '04-01'))->seasonYearFor(new \DateTimeImmutable('2025-01-01')); (new SeasonCalendar('xx-yy', '04-01'))->seasonYearFor(new \DateTimeImmutable('2025-01-01'));
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('currentOrUpcomingDates')]
* @dataProvider currentOrUpcomingDates
*/
public function testCurrentOrUpcomingSeasonYear(string $date, int $expected): void public function testCurrentOrUpcomingSeasonYear(string $date, int $expected): void
{ {
$this->assertSame( $this->assertSame(
@@ -117,9 +111,7 @@ class SeasonCalendarTest extends TestCase
$this->assertSame('2025-09-30', $end->format('Y-m-d')); $this->assertSame('2025-09-30', $end->format('Y-m-d'));
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('provideUpcomingSeasonDates')]
* @dataProvider provideUpcomingSeasonDates
*/
public function testTheCurrentOrUpcomingSeasonYear(string $date, int $expected): void public function testTheCurrentOrUpcomingSeasonYear(string $date, int $expected): void
{ {
$calendar = new SeasonCalendar('11-01', '04-01'); $calendar = new SeasonCalendar('11-01', '04-01');
+1 -3
View File
@@ -31,9 +31,7 @@ class SeasonTaskTest extends TestCase
$this->assertSame($labels, array_unique($labels)); $this->assertSame($labels, array_unique($labels));
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('entries')]
* @dataProvider entries
*/
public function testTheAgreedEntryList( public function testTheAgreedEntryList(
SeasonTask $task, SeasonTask $task,
string $label, string $label,
@@ -67,10 +67,10 @@ class DestinationTraitTest extends TestCase
*/ */
private function harness(?Hotel $hotel, array $pickups = []): object private function harness(?Hotel $hotel, array $pickups = []): object
{ {
$hotelProvider = $this->createMock(HotelDataProvider::class); $hotelProvider = $this->createStub(HotelDataProvider::class);
$hotelProvider->method('get')->willReturn($hotel); $hotelProvider->method('get')->willReturn($hotel);
$pickupProvider = $this->createMock(PickupDataProvider::class); $pickupProvider = $this->createStub(PickupDataProvider::class);
$pickupProvider->method('get')->willReturnCallback(fn ($id) => $pickups[$id] ?? null); $pickupProvider->method('get')->willReturnCallback(fn ($id) => $pickups[$id] ?? null);
return new class($hotelProvider, $pickupProvider) { return new class($hotelProvider, $pickupProvider) {
@@ -79,9 +79,8 @@ class ApplicationFormControllerTest extends WebTestCase
* date element straight to json_encode sends an object, and its keys are the whole diagnosis. * date element straight to json_encode sends an object, and its keys are the whole diagnosis.
* *
* Never the value itself - a rejected payload is still personal data. * Never the value itself - a rejected payload is still personal data.
*
* @dataProvider unusableBirthDateTypes
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('unusableBirthDateTypes')]
public function testARejectionNamesTheShapeThatArrived(mixed $birthDate, string $received): void public function testARejectionNamesTheShapeThatArrived(mixed $birthDate, string $received): void
{ {
$this->post(['birthDate' => $birthDate] + $this->payload()); $this->post(['birthDate' => $birthDate] + $this->payload());
@@ -258,9 +257,7 @@ class ApplicationFormControllerTest extends WebTestCase
$this->assertSame([], $submission->getDetails()); $this->assertSame([], $submission->getDetails());
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('requiredFields')]
* @dataProvider requiredFields
*/
public function testAPayloadMissingARequiredFieldIsRejected(string $field): void public function testAPayloadMissingARequiredFieldIsRejected(string $field): void
{ {
$payload = $this->payload(); $payload = $this->payload();
@@ -277,9 +274,8 @@ class ApplicationFormControllerTest extends WebTestCase
/** /**
* An empty string is the shape a form posts for a field the visitor left blank, and it is as * An empty string is the shape a form posts for a field the visitor left blank, and it is as
* unusable as an absent key - except for eu, where "" is a lawful no and has its own case. * unusable as an absent key - except for eu, where "" is a lawful no and has its own case.
*
* @dataProvider requiredFields
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('requiredFields')]
public function testAPayloadWithAnEmptyRequiredFieldIsRejected(string $field): void public function testAPayloadWithAnEmptyRequiredFieldIsRejected(string $field): void
{ {
if ('eu' === $field) { if ('eu' === $field) {
@@ -315,9 +311,8 @@ class ApplicationFormControllerTest extends WebTestCase
* The one field whose format is nailed down: provisioning parses it as a date, so the day the * The one field whose format is nailed down: provisioning parses it as a date, so the day the
* TYPO3 side switches a form back to a free-text birthday has to be a 400 here rather than a * TYPO3 side switches a form back to a free-text birthday has to be a 400 here rather than a
* failure in front of a reviewer weeks later. * failure in front of a reviewer weeks later.
*
* @dataProvider unusableBirthDates
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('unusableBirthDates')]
public function testAnUnusableBirthDateIsRejected(string $birthDate): void public function testAnUnusableBirthDateIsRejected(string $birthDate): void
{ {
$this->post(['birthDate' => $birthDate] + $this->payload()); $this->post(['birthDate' => $birthDate] + $this->payload());
@@ -380,9 +375,8 @@ class ApplicationFormControllerTest extends WebTestCase
/** /**
* Case is the sender's business, not a reason to lose an application: every spelling a form * Case is the sender's business, not a reason to lose an application: every spelling a form
* can post lands on the same stored value. * can post lands on the same stored value.
*
* @dataProvider genderSpellings
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('genderSpellings')]
public function testAGenderIsReadWhateverItsCase(string $posted, string $stored): void public function testAGenderIsReadWhateverItsCase(string $posted, string $stored): void
{ {
$this->post(['gender' => $posted] + $this->payload()); $this->post(['gender' => $posted] + $this->payload());
+4 -6
View File
@@ -44,9 +44,7 @@ class EmailTextMailRenderingTest extends KernelTestCase
EmailTextKey::APPLICATION_FORM_FOLLOW_UP, EmailTextKey::APPLICATION_FORM_FOLLOW_UP,
]; ];
/** #[\PHPUnit\Framework\Attributes\DataProvider('provideKeys')]
* @dataProvider provideKeys
*/
public function testTheMailRenders(EmailTextKey $key): void public function testTheMailRenders(EmailTextKey $key): void
{ {
self::bootKernel(); self::bootKernel();
@@ -63,7 +61,7 @@ class EmailTextMailRenderingTest extends KernelTestCase
// Renders the delivered wording: the test environment has no database, and the // Renders the delivered wording: the test environment has no database, and the
// defaults are what a mail falls back to anyway. // defaults are what a mail falls back to anyway.
$repository = $this->createMock(EmailTextRepository::class); $repository = $this->createStub(EmailTextRepository::class);
$repository->method('findByKey')->willReturn(null); $repository->method('findByKey')->willReturn(null);
$text = (new EmailTextRenderer( $text = (new EmailTextRenderer(
@@ -152,7 +150,7 @@ class EmailTextMailRenderingTest extends KernelTestCase
self::bootKernel(); self::bootKernel();
$container = self::getContainer(); $container = self::getContainer();
$repository = $this->createMock(EmailTextRepository::class); $repository = $this->createStub(EmailTextRepository::class);
$repository->method('findByKey')->willReturn(null); $repository->method('findByKey')->willReturn(null);
$renderer = new EmailTextRenderer( $renderer = new EmailTextRenderer(
@@ -173,7 +171,7 @@ class EmailTextMailRenderingTest extends KernelTestCase
self::bootKernel(); self::bootKernel();
$container = self::getContainer(); $container = self::getContainer();
$repository = $this->createMock(EmailTextRepository::class); $repository = $this->createStub(EmailTextRepository::class);
$repository->method('findByKey')->willReturn(null); $repository->method('findByKey')->willReturn(null);
$text = (new EmailTextRenderer( $text = (new EmailTextRenderer(
+3 -3
View File
@@ -228,7 +228,7 @@ class EmailTextRendererTest extends KernelTestCase
*/ */
public function testGivenValuesAreRenderedInsteadOfTheStoredOnes(): void public function testGivenValuesAreRenderedInsteadOfTheStoredOnes(): void
{ {
$repository = $this->createMock(EmailTextRepository::class); $repository = $this->createStub(EmailTextRepository::class);
$repository $repository
->method('findByKey') ->method('findByKey')
->willReturn($this->emailText(subject: 'Gespeichert', body: 'Gespeicherter Text')) ->willReturn($this->emailText(subject: 'Gespeichert', body: 'Gespeicherter Text'))
@@ -264,7 +264,7 @@ class EmailTextRendererTest extends KernelTestCase
$renderer = new EmailTextRenderer( $renderer = new EmailTextRenderer(
self::getContainer()->get(EmailTextCatalog::class), self::getContainer()->get(EmailTextCatalog::class),
$this->createMock(EmailTextRepository::class), $this->createStub(EmailTextRepository::class),
self::getContainer()->get(MailBodyRenderer::class) self::getContainer()->get(MailBodyRenderer::class)
); );
@@ -286,7 +286,7 @@ class EmailTextRendererTest extends KernelTestCase
*/ */
private function render(?EmailText $emailText, array $placeholders): \App\Model\RenderedEmailTextDto private function render(?EmailText $emailText, array $placeholders): \App\Model\RenderedEmailTextDto
{ {
$repository = $this->createMock(EmailTextRepository::class); $repository = $this->createStub(EmailTextRepository::class);
$repository $repository
->method('findByKey') ->method('findByKey')
->willReturn($emailText) ->willReturn($emailText)
@@ -13,16 +13,19 @@ use App\EventListener\DatevEmailSubscriber;
use App\Model\EmailPathAttachmentDto; use App\Model\EmailPathAttachmentDto;
use App\Service\Upload\UploadHandler; use App\Service\Upload\UploadHandler;
use Flagception\Manager\FeatureManagerInterface; use Flagception\Manager\FeatureManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
#[AllowMockObjectsWithoutExpectations]
class DatevEmailSubscriberTest extends TestCase class DatevEmailSubscriberTest extends TestCase
{ {
private Mailer&MockObject $mailer; private Mailer&MockObject $mailer;
private UploadHandler&MockObject $uploadHandler; private UploadHandler&MockObject $uploadHandler;
private LoggerInterface&MockObject $logger; private LoggerInterface&MockObject $logger;
private FeatureManagerInterface&MockObject $featureManager; private FeatureManagerInterface&Stub $featureManager;
private DatevEmailSubscriber $subscriber; private DatevEmailSubscriber $subscriber;
protected function setUp(): void protected function setUp(): void
@@ -30,8 +33,8 @@ class DatevEmailSubscriberTest extends TestCase
$this->mailer = $this->createMock(Mailer::class); $this->mailer = $this->createMock(Mailer::class);
$this->uploadHandler = $this->createMock(UploadHandler::class); $this->uploadHandler = $this->createMock(UploadHandler::class);
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
$this->featureManager = $this->createMock(FeatureManagerInterface::class); $this->featureManager = $this->createStub(FeatureManagerInterface::class);
$this->featureManager->method('isActive')->with('datev_email')->willReturn(true); $this->featureManager->method('isActive')->willReturnCallback(static fn (string $name): bool => 'datev_email' === $name);
$this->subscriber = new DatevEmailSubscriber( $this->subscriber = new DatevEmailSubscriber(
$this->mailer, $this->mailer,
@@ -53,7 +56,7 @@ class DatevEmailSubscriberTest extends TestCase
public function testSkipsNonInvoiceDocuments(): void public function testSkipsNonInvoiceDocuments(): void
{ {
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getType')->willReturn(Upload::TYPE_CONTRACT); $document->method('getType')->willReturn(Upload::TYPE_CONTRACT);
$this->mailer $this->mailer
@@ -66,7 +69,7 @@ class DatevEmailSubscriberTest extends TestCase
public function testSkipsDocumentWithoutDisposition(): void public function testSkipsDocumentWithoutDisposition(): void
{ {
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getType')->willReturn(Upload::TYPE_INVOICE); $document->method('getType')->willReturn(Upload::TYPE_INVOICE);
$document->method('getDisposition')->willReturn(null); $document->method('getDisposition')->willReturn(null);
$document->method('getId')->willReturn(1); $document->method('getId')->willReturn(1);
@@ -86,10 +89,10 @@ class DatevEmailSubscriberTest extends TestCase
public function testSkipsDispositionWithoutTeamer(): void public function testSkipsDispositionWithoutTeamer(): void
{ {
$disposition = $this->createMock(Disposition::class); $disposition = $this->createStub(Disposition::class);
$disposition->method('getTeamer')->willReturn(null); $disposition->method('getTeamer')->willReturn(null);
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getType')->willReturn(Upload::TYPE_INVOICE); $document->method('getType')->willReturn(Upload::TYPE_INVOICE);
$document->method('getDisposition')->willReturn($disposition); $document->method('getDisposition')->willReturn($disposition);
$document->method('getId')->willReturn(2); $document->method('getId')->willReturn(2);
@@ -109,13 +112,13 @@ class DatevEmailSubscriberTest extends TestCase
public function testSkipsMissingAttachmentFile(): void public function testSkipsMissingAttachmentFile(): void
{ {
$teamer = $this->createMock(Teamer::class); $teamer = $this->createStub(Teamer::class);
$teamer->method('getFullName')->willReturn('Doe, John'); $teamer->method('getFullName')->willReturn('Doe, John');
$disposition = $this->createMock(Disposition::class); $disposition = $this->createStub(Disposition::class);
$disposition->method('getTeamer')->willReturn($teamer); $disposition->method('getTeamer')->willReturn($teamer);
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getType')->willReturn(Upload::TYPE_INVOICE); $document->method('getType')->willReturn(Upload::TYPE_INVOICE);
$document->method('getDisposition')->willReturn($disposition); $document->method('getDisposition')->willReturn($disposition);
$document->method('getId')->willReturn(3); $document->method('getId')->willReturn(3);
@@ -145,14 +148,14 @@ class DatevEmailSubscriberTest extends TestCase
public function testSendsEmailWithAttachment(): void public function testSendsEmailWithAttachment(): void
{ {
$teamer = $this->createMock(Teamer::class); $teamer = $this->createStub(Teamer::class);
$teamer->method('getFullName')->willReturn('Doe, John'); $teamer->method('getFullName')->willReturn('Doe, John');
$teamer->method('__toString')->willReturn('Doe, John'); $teamer->method('__toString')->willReturn('Doe, John');
$disposition = $this->createMock(Disposition::class); $disposition = $this->createStub(Disposition::class);
$disposition->method('getTeamer')->willReturn($teamer); $disposition->method('getTeamer')->willReturn($teamer);
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getDisposition')->willReturn($disposition); $document->method('getDisposition')->willReturn($disposition);
$document->method('getType')->willReturn(Upload::TYPE_INVOICE); $document->method('getType')->willReturn(Upload::TYPE_INVOICE);
$document->method('getId')->willReturn(42); $document->method('getId')->willReturn(42);
@@ -21,6 +21,7 @@ use App\EventListener\EmailNotificationSubscriber;
use App\Model\ApplicationStatusDto; use App\Model\ApplicationStatusDto;
use App\Repository\UserRepository; use App\Repository\UserRepository;
use App\Service\Pdf\ContractRenderer; use App\Service\Pdf\ContractRenderer;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@@ -28,6 +29,7 @@ use PHPUnit\Framework\TestCase;
* A deleted teamer must never be mailed again - this is the point of the deletion, so * A deleted teamer must never be mailed again - this is the point of the deletion, so
* every handler that writes to a teamer is covered here. * every handler that writes to a teamer is covered here.
*/ */
#[AllowMockObjectsWithoutExpectations]
class EmailNotificationSubscriberTest extends TestCase class EmailNotificationSubscriberTest extends TestCase
{ {
private Mailer&MockObject $mailer; private Mailer&MockObject $mailer;
@@ -41,9 +43,9 @@ class EmailNotificationSubscriberTest extends TestCase
$this->subscriber = new EmailNotificationSubscriber( $this->subscriber = new EmailNotificationSubscriber(
$this->mailer, $this->mailer,
$this->createMock(UserRepository::class), $this->createStub(UserRepository::class),
$this->contractRenderer, $this->contractRenderer,
$this->createMock(MailPlaceholderFactory::class), $this->createStub(MailPlaceholderFactory::class),
7, 7,
); );
} }
@@ -16,12 +16,15 @@ use App\EventListener\InvalidateApplicationsListener;
use App\Repository\ApplicationRepository; use App\Repository\ApplicationRepository;
use Carbon\CarbonPeriodImmutable; use Carbon\CarbonPeriodImmutable;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\Event;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
#[AllowMockObjectsWithoutExpectations]
class InvalidateApplicationsListenerTest extends TestCase class InvalidateApplicationsListenerTest extends TestCase
{ {
private ApplicationRepository&MockObject $applicationRepository; private ApplicationRepository&MockObject $applicationRepository;
@@ -38,7 +41,7 @@ class InvalidateApplicationsListenerTest extends TestCase
{ {
$this->applicationRepository = $this->createMock(ApplicationRepository::class); $this->applicationRepository = $this->createMock(ApplicationRepository::class);
$this->entityManager = $this->createMock(EntityManagerInterface::class); $this->entityManager = $this->createMock(EntityManagerInterface::class);
$eventDispatcher = $this->createMock(EventDispatcherInterface::class); $eventDispatcher = $this->createStub(EventDispatcherInterface::class);
$this->removedApplications = []; $this->removedApplications = [];
$this->dispatchedEvents = []; $this->dispatchedEvents = [];
@@ -62,13 +65,13 @@ class InvalidateApplicationsListenerTest extends TestCase
$this->applicationRepository, $this->applicationRepository,
$this->entityManager, $this->entityManager,
$eventDispatcher, $eventDispatcher,
$this->createMock(LoggerInterface::class) $this->createStub(LoggerInterface::class)
); );
} }
public function testIgnoresNonContractDocuments(): void public function testIgnoresNonContractDocuments(): void
{ {
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getType')->willReturn(Upload::TYPE_INVOICE); $document->method('getType')->willReturn(Upload::TYPE_INVOICE);
$this->applicationRepository->expects($this->never())->method('findOverlappingForTeamer'); $this->applicationRepository->expects($this->never())->method('findOverlappingForTeamer');
@@ -188,51 +191,51 @@ class InvalidateApplicationsListenerTest extends TestCase
} }
} }
private function createTeamer(bool $allowOverlapping = false): Teamer&MockObject private function createTeamer(bool $allowOverlapping = false): Teamer&Stub
{ {
$teamer = $this->createMock(Teamer::class); $teamer = $this->createStub(Teamer::class);
$teamer->method('isAllowOverlappingApplications')->willReturn($allowOverlapping); $teamer->method('isAllowOverlappingApplications')->willReturn($allowOverlapping);
$teamer->method('getUuid')->willReturn('teamer-uuid'); $teamer->method('getUuid')->willReturn('teamer-uuid');
return $teamer; return $teamer;
} }
private function createContract(?CarbonPeriodImmutable $period, Teamer $teamer): Upload&MockObject private function createContract(?CarbonPeriodImmutable $period, Teamer $teamer): Upload&Stub
{ {
$assignment = $this->createMock(Assignment::class); $assignment = $this->createStub(Assignment::class);
if (null === $period) { if (null === $period) {
$assignment->method('getDestination')->willReturn(null); $assignment->method('getDestination')->willReturn(null);
} else { } else {
$destination = $this->createMock(Destination::class); $destination = $this->createStub(Destination::class);
$destination->method('getDateFrom')->willReturn($period->getStartDate()->toDateTimeImmutable()); $destination->method('getDateFrom')->willReturn($period->getStartDate()->toDateTimeImmutable());
$destination->method('getDateTo')->willReturn($period->getEndDate()->toDateTimeImmutable()); $destination->method('getDateTo')->willReturn($period->getEndDate()->toDateTimeImmutable());
$assignment->method('getDestination')->willReturn($destination); $assignment->method('getDestination')->willReturn($destination);
} }
$disposition = $this->createMock(Disposition::class); $disposition = $this->createStub(Disposition::class);
$disposition->method('getAssignment')->willReturn($assignment); $disposition->method('getAssignment')->willReturn($assignment);
$disposition->method('getTeamer')->willReturn($teamer); $disposition->method('getTeamer')->willReturn($teamer);
$document = $this->createMock(Upload::class); $document = $this->createStub(Upload::class);
$document->method('getType')->willReturn(Upload::TYPE_CONTRACT); $document->method('getType')->willReturn(Upload::TYPE_CONTRACT);
$document->method('getDisposition')->willReturn($disposition); $document->method('getDisposition')->willReturn($disposition);
return $document; return $document;
} }
private function createApplication(): Application&MockObject private function createApplication(): Application&Stub
{ {
$destination = $this->createMock(Destination::class); $destination = $this->createStub(Destination::class);
$destination->method('getHotelCode')->willReturn('TST'); $destination->method('getHotelCode')->willReturn('TST');
$destination->method('getDateFrom')->willReturn(new \DateTimeImmutable('2025-01-12')); $destination->method('getDateFrom')->willReturn(new \DateTimeImmutable('2025-01-12'));
$destination->method('getDateTo')->willReturn(new \DateTimeImmutable('2025-01-18')); $destination->method('getDateTo')->willReturn(new \DateTimeImmutable('2025-01-18'));
$assignment = $this->createMock(Assignment::class); $assignment = $this->createStub(Assignment::class);
$assignment->method('getDestination')->willReturn($destination); $assignment->method('getDestination')->willReturn($destination);
$assignment->method('getUuid')->willReturn('assignment-uuid'); $assignment->method('getUuid')->willReturn('assignment-uuid');
$application = $this->createMock(Application::class); $application = $this->createStub(Application::class);
$application->method('getUuid')->willReturn('application-uuid'); $application->method('getUuid')->willReturn('application-uuid');
$application->method('getAssignment')->willReturn($assignment); $application->method('getAssignment')->willReturn($assignment);
@@ -24,6 +24,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Event\PostFlushEventArgs; use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\UnitOfWork;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@@ -32,6 +33,7 @@ use PHPUnit\Framework\TestCase;
* profile change overwrites its own history - so the thing worth pinning is *when* a row * profile change overwrites its own history - so the thing worth pinning is *when* a row
* gets written and when it must not. * gets written and when it must not.
*/ */
#[AllowMockObjectsWithoutExpectations]
class StatisticsChangeSetListenerTest extends TestCase class StatisticsChangeSetListenerTest extends TestCase
{ {
private StatisticsRecorder&MockObject $recorder; private StatisticsRecorder&MockObject $recorder;
@@ -501,7 +503,7 @@ class StatisticsChangeSetListenerTest extends TestCase
$byEntity[$entity] = $changeSet; $byEntity[$entity] = $changeSet;
} }
$unitOfWork = $this->createMock(UnitOfWork::class); $unitOfWork = $this->createStub(UnitOfWork::class);
$unitOfWork->method('getScheduledEntityUpdates')->willReturn($entities); $unitOfWork->method('getScheduledEntityUpdates')->willReturn($entities);
$unitOfWork->method('getScheduledEntityInsertions')->willReturn($insertions); $unitOfWork->method('getScheduledEntityInsertions')->willReturn($insertions);
$unitOfWork->method('getScheduledEntityDeletions')->willReturn($deletions); $unitOfWork->method('getScheduledEntityDeletions')->willReturn($deletions);
@@ -510,7 +512,7 @@ class StatisticsChangeSetListenerTest extends TestCase
->willReturnCallback(static fn (object $entity): array => $byEntity[$entity] ?? []) ->willReturnCallback(static fn (object $entity): array => $byEntity[$entity] ?? [])
; ;
$entityManager = $this->createMock(EntityManagerInterface::class); $entityManager = $this->createStub(EntityManagerInterface::class);
$entityManager->method('getUnitOfWork')->willReturn($unitOfWork); $entityManager->method('getUnitOfWork')->willReturn($unitOfWork);
return new OnFlushEventArgs($entityManager); return new OnFlushEventArgs($entityManager);
@@ -518,7 +520,7 @@ class StatisticsChangeSetListenerTest extends TestCase
private function postFlushArgs(): PostFlushEventArgs private function postFlushArgs(): PostFlushEventArgs
{ {
return new PostFlushEventArgs($this->createMock(EntityManagerInterface::class)); return new PostFlushEventArgs($this->createStub(EntityManagerInterface::class));
} }
/** /**
+1
View File
@@ -14,6 +14,7 @@ use Symfony\Component\Form\Test\TypeTestCase;
* The rows attribute is deliberately not part of it: textarea_autosize_controller.js * The rows attribute is deliberately not part of it: textarea_autosize_controller.js
* overwrites rows on connect, which is why the floor travels as min_rows instead. * overwrites rows on connect, which is why the floor travels as min_rows instead.
*/ */
#[\PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations]
class AutosizeTextareaTypeTest extends TypeTestCase class AutosizeTextareaTypeTest extends TypeTestCase
{ {
public function testTheControllerAndItsResizeActionAreWiredUp(): void public function testTheControllerAndItsResizeActionAreWiredUp(): void
+1 -1
View File
@@ -58,7 +58,7 @@ class InjectUserProcessorTest extends TestCase
private function process(?InMemoryUser $user, string $sapi = 'fpm-fcgi'): LogRecord private function process(?InMemoryUser $user, string $sapi = 'fpm-fcgi'): LogRecord
{ {
$security = $this->createMock(Security::class); $security = $this->createStub(Security::class);
$security->method('getUser')->willReturn($user); $security->method('getUser')->willReturn($user);
$processor = new InjectUserProcessor($security, $sapi); $processor = new InjectUserProcessor($security, $sapi);
+1 -1
View File
@@ -20,7 +20,7 @@ class UserDataProcessorTest extends TestCase
{ {
public function testAnApiFirewallUserGetsNoIdInsteadOfAnError(): void public function testAnApiFirewallUserGetsNoIdInsteadOfAnError(): void
{ {
$security = $this->createMock(Security::class); $security = $this->createStub(Security::class);
$security->method('getUser')->willReturn(new InMemoryUser('api', null, ['ROLE_API'])); $security->method('getUser')->willReturn(new InMemoryUser('api', null, ['ROLE_API']));
$security->method('getToken')->willReturn(null); $security->method('getToken')->willReturn(null);
+1 -2
View File
@@ -58,9 +58,8 @@ class TeamerMenuBackItemTest extends KernelTestCase
/** /**
* The regression guard: reachable e.g. after the status update in * The regression guard: reachable e.g. after the status update in
* Admin\Teamer\SkillsController, which redirects without carrying "r" forward. * Admin\Teamer\SkillsController, which redirects without carrying "r" forward.
*
* @dataProvider builderProvider
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('builderProvider')]
public function testWithoutAnyReturnUrlTheOverviewIsLinked(string $builderClass): void public function testWithoutAnyReturnUrlTheOverviewIsLinked(string $builderClass): void
{ {
$this->pushRequest(); $this->pushRequest();
+2 -5
View File
@@ -27,9 +27,7 @@ class DestinationDtoTest extends TestCase
$this->assertSame(['at', 'ch', 'fr', 'it', 'de', 'nl'], DestinationDto::countryCodes()); $this->assertSame(['at', 'ch', 'fr', 'it', 'de', 'nl'], DestinationDto::countryCodes());
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('isoCountryCodes')]
* @dataProvider isoCountryCodes
*/
public function testAnIsoCountryCodeIsAccepted(string $code): void public function testAnIsoCountryCodeIsAccepted(string $code): void
{ {
$this->assertCount(0, $this->validateCountry($code)); $this->assertCount(0, $this->validateCountry($code));
@@ -37,9 +35,8 @@ class DestinationDtoTest extends TestCase
/** /**
* The four that the form offered and the constraint refused. * The four that the form offered and the constraint refused.
*
* @dataProvider busProNetCountryAbbreviations
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('busProNetCountryAbbreviations')]
public function testABusProNetAbbreviationIsNoLongerAccepted(string $abbreviation): void public function testABusProNetAbbreviationIsNoLongerAccepted(string $abbreviation): void
{ {
$this->assertCount(1, $this->validateCountry($abbreviation)); $this->assertCount(1, $this->validateCountry($abbreviation));
+1 -2
View File
@@ -14,9 +14,8 @@ class ApiClientTest extends TestCase
/** /**
* The whole point of the calendar-month argument: the app never has to know that the * The whole point of the calendar-month argument: the app never has to know that the
* API counts from zero. * API counts from zero.
*
* @dataProvider provideMonths
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('provideMonths')]
public function testItTranslatesTheCalendarMonthIntoTheApiIndex(int $month, string $expectedPath): void public function testItTranslatesTheCalendarMonthIntoTheApiIndex(int $month, string $expectedPath): void
{ {
$requested = null; $requested = null;
+9 -6
View File
@@ -13,7 +13,9 @@ use App\Entity\User;
use App\RequiredTeamerCheck\RequiredTeamerCheckRegistry; use App\RequiredTeamerCheck\RequiredTeamerCheckRegistry;
use App\Security\BpnAuthenticator; use App\Security\BpnAuthenticator;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -23,14 +25,15 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
#[AllowMockObjectsWithoutExpectations]
class BpnAuthenticatorTest extends TestCase class BpnAuthenticatorTest extends TestCase
{ {
private ApiClient&MockObject $apiClient; private ApiClient&Stub $apiClient;
private UserDataHandler&MockObject $userDataHandler; private UserDataHandler&MockObject $userDataHandler;
protected function setUp(): void protected function setUp(): void
{ {
$this->apiClient = $this->createMock(ApiClient::class); $this->apiClient = $this->createStub(ApiClient::class);
$this->userDataHandler = $this->createMock(UserDataHandler::class); $this->userDataHandler = $this->createMock(UserDataHandler::class);
} }
@@ -148,12 +151,12 @@ class BpnAuthenticatorTest extends TestCase
private function loadUser(): ?User private function loadUser(): ?User
{ {
$authenticator = new BpnAuthenticator( $authenticator = new BpnAuthenticator(
$this->createMock(UrlGeneratorInterface::class), $this->createStub(UrlGeneratorInterface::class),
$this->createMock(EntityManagerInterface::class), $this->createStub(EntityManagerInterface::class),
$this->apiClient, $this->apiClient,
$this->createMock(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->userDataHandler, $this->userDataHandler,
$this->createMock(RequiredTeamerCheckRegistry::class), $this->createStub(RequiredTeamerCheckRegistry::class),
); );
$request = new Request(request: [ $request = new Request(request: [
+8 -6
View File
@@ -13,6 +13,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Flagception\Manager\FeatureManagerInterface; use Flagception\Manager\FeatureManagerInterface;
use League\OAuth2\Client\Token\AccessToken; use League\OAuth2\Client\Token\AccessToken;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@@ -25,6 +26,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
#[AllowMockObjectsWithoutExpectations]
class MyEpAuthenticatorTest extends TestCase class MyEpAuthenticatorTest extends TestCase
{ {
private EntityManagerInterface&MockObject $entityManager; private EntityManagerInterface&MockObject $entityManager;
@@ -425,21 +427,21 @@ class MyEpAuthenticatorTest extends TestCase
private function createAuthenticator(array $userinfo, bool $featureActive = true, ?MockHttpClient $httpClient = null): MyEpAuthenticator private function createAuthenticator(array $userinfo, bool $featureActive = true, ?MockHttpClient $httpClient = null): MyEpAuthenticator
{ {
$client = $this->createMock(MyEpClient::class); $client = $this->createStub(MyEpClient::class);
$client->method('fetchAccessToken')->willReturn(new AccessToken(['access_token' => 'token'])); $client->method('fetchAccessToken')->willReturn(new AccessToken(['access_token' => 'token']));
$featureManager = $this->createMock(FeatureManagerInterface::class); $featureManager = $this->createStub(FeatureManagerInterface::class);
$featureManager->method('isActive')->willReturn($featureActive); $featureManager->method('isActive')->willReturn($featureActive);
return new MyEpAuthenticator( return new MyEpAuthenticator(
$client, $client,
$httpClient ?? $this->userinfoClient($userinfo), $httpClient ?? $this->userinfoClient($userinfo),
new UserDataHandler($this->entityManager, $this->createMock(LoggerInterface::class)), new UserDataHandler($this->entityManager, $this->createStub(LoggerInterface::class)),
$this->entityManager, $this->entityManager,
$this->createMock(UrlGeneratorInterface::class), $this->createStub(UrlGeneratorInterface::class),
$this->createMock(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$featureManager, $featureManager,
$this->createMock(RequiredTeamerCheckRegistry::class), $this->createStub(RequiredTeamerCheckRegistry::class),
); );
} }
} }
+2 -2
View File
@@ -137,13 +137,13 @@ class MyEpClientTest extends TestCase
private function createClient(): MyEpClient private function createClient(): MyEpClient
{ {
$urlGenerator = $this->createMock(UrlGeneratorInterface::class); $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
$urlGenerator $urlGenerator
->method('generate') ->method('generate')
->willReturn('https://myep-team.example.org/myep-auth/check') ->willReturn('https://myep-team.example.org/myep-auth/check')
; ;
return new MyEpClient($urlGenerator, $this->createMock(LoggerInterface::class), [ return new MyEpClient($urlGenerator, $this->createStub(LoggerInterface::class), [
'myep_oauth2_client_id' => 'client-id', 'myep_oauth2_client_id' => 'client-id',
'myep_oauth2_client_secret' => 'client-secret', 'myep_oauth2_client_secret' => 'client-secret',
'myep_oauth2_url_authorize' => 'https://my.example.org/authorize', 'myep_oauth2_url_authorize' => 'https://my.example.org/authorize',
@@ -19,10 +19,7 @@ class DriverLicenseRequiredCheckTest extends TestCase
$this->check = new DriverLicenseRequiredCheck(); $this->check = new DriverLicenseRequiredCheck();
} }
#[\PHPUnit\Framework\Attributes\DataProvider('mixedRoleProvider')]
/**
* @dataProvider mixedRoleProvider
*/
public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void
{ {
$user = $this->createTeamerUser(); $user = $this->createTeamerUser();
@@ -31,7 +28,7 @@ class DriverLicenseRequiredCheckTest extends TestCase
$this->assertFalse($this->check->appliesTo($user)); $this->assertFalse($this->check->appliesTo($user));
} }
public function mixedRoleProvider(): array public static function mixedRoleProvider(): array
{ {
return [ return [
['ROLE_TEAM_ADMIN'], ['ROLE_TEAM_ADMIN'],
@@ -19,9 +19,7 @@ class FinancialDataRequiredCheckTest extends TestCase
$this->check = new FinancialDataRequiredCheck(); $this->check = new FinancialDataRequiredCheck();
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('mixedRoleProvider')]
* @dataProvider mixedRoleProvider
*/
public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void
{ {
$user = $this->createTeamerUser(); $user = $this->createTeamerUser();
@@ -30,7 +28,7 @@ class FinancialDataRequiredCheckTest extends TestCase
$this->assertFalse($this->check->appliesTo($user)); $this->assertFalse($this->check->appliesTo($user));
} }
public function mixedRoleProvider(): array public static function mixedRoleProvider(): array
{ {
return [ return [
['ROLE_TEAM_ADMIN'], ['ROLE_TEAM_ADMIN'],
@@ -76,9 +74,7 @@ class FinancialDataRequiredCheckTest extends TestCase
$this->assertFalse($this->check->isSatisfied($user)); $this->assertFalse($this->check->isSatisfied($user));
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('missingBankAccountFieldProvider')]
* @dataProvider missingBankAccountFieldProvider
*/
public function testIsNotSatisfiedWhenBankAccountFieldIsMissing(string $setter): void public function testIsNotSatisfiedWhenBankAccountFieldIsMissing(string $setter): void
{ {
$bankAccount = $this->createBankAccount(); $bankAccount = $this->createBankAccount();
@@ -93,7 +89,7 @@ class FinancialDataRequiredCheckTest extends TestCase
$this->assertFalse($this->check->isSatisfied($user)); $this->assertFalse($this->check->isSatisfied($user));
} }
public function missingBankAccountFieldProvider(): array public static function missingBankAccountFieldProvider(): array
{ {
return [ return [
['setIban'], ['setIban'],
@@ -19,9 +19,7 @@ class MealPreferenceRequiredCheckTest extends TestCase
$this->check = new MealPreferenceRequiredCheck(); $this->check = new MealPreferenceRequiredCheck();
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('mixedRoleProvider')]
* @dataProvider mixedRoleProvider
*/
public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void
{ {
$user = $this->createTeamerUser(); $user = $this->createTeamerUser();
@@ -30,7 +28,7 @@ class MealPreferenceRequiredCheckTest extends TestCase
$this->assertFalse($this->check->appliesTo($user)); $this->assertFalse($this->check->appliesTo($user));
} }
public function mixedRoleProvider(): array public static function mixedRoleProvider(): array
{ {
return [ return [
['ROLE_TEAM_ADMIN'], ['ROLE_TEAM_ADMIN'],
@@ -30,9 +30,7 @@ class PersonalDataVerificationRequiredCheckTest extends TestCase
$this->assertTrue($this->createCheck()->appliesTo($user)); $this->assertTrue($this->createCheck()->appliesTo($user));
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('mixedRoleProvider')]
* @dataProvider mixedRoleProvider
*/
public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void public function testDoesNotApplyToExcludedMixedRoleUsersWithTeamerRole(string $excludedRole): void
{ {
$user = (new User())->setRoles([$excludedRole, 'ROLE_TEAMER']); $user = (new User())->setRoles([$excludedRole, 'ROLE_TEAMER']);
@@ -40,7 +38,7 @@ class PersonalDataVerificationRequiredCheckTest extends TestCase
$this->assertFalse($this->createCheck()->appliesTo($user)); $this->assertFalse($this->createCheck()->appliesTo($user));
} }
public function mixedRoleProvider(): array public static function mixedRoleProvider(): array
{ {
return [ return [
['ROLE_TEAM_ADMIN'], ['ROLE_TEAM_ADMIN'],
+9 -14
View File
@@ -10,7 +10,7 @@ use App\Entity\Disposition;
use App\Entity\Teamer; use App\Entity\Teamer;
use App\Entity\User; use App\Entity\User;
use App\Security\Voter\DispositionVoter; use App\Security\Voter\DispositionVoter;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@@ -23,16 +23,14 @@ use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
*/ */
class DispositionVoterTest extends TestCase class DispositionVoterTest extends TestCase
{ {
private Security&MockObject $security; private Security&Stub $security;
protected function setUp(): void protected function setUp(): void
{ {
$this->security = $this->createMock(Security::class); $this->security = $this->createStub(Security::class);
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('documentAndFeedbackAttributes')]
* @dataProvider documentAndFeedbackAttributes
*/
public function testAnAdminIsDeniedOnASkipFormalitiesAssignment(string $attribute): void public function testAnAdminIsDeniedOnASkipFormalitiesAssignment(string $attribute): void
{ {
$this->security->method('isGranted')->willReturn(true); $this->security->method('isGranted')->willReturn(true);
@@ -46,9 +44,8 @@ class DispositionVoterTest extends TestCase
/** /**
* The same admin on a normal assignment must still get through - the flag is the only thing * The same admin on a normal assignment must still get through - the flag is the only thing
* that may take these away. * that may take these away.
*
* @dataProvider documentAndFeedbackAttributes
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('documentAndFeedbackAttributes')]
public function testTheSameAdminIsGrantedOnANormalAssignment(string $attribute): void public function testTheSameAdminIsGrantedOnANormalAssignment(string $attribute): void
{ {
$this->security->method('isGranted')->willReturn(true); $this->security->method('isGranted')->willReturn(true);
@@ -91,9 +88,8 @@ class DispositionVoterTest extends TestCase
* transition, because there is none to derive it from: while the Honorarnote is being checked * transition, because there is none to derive it from: while the Honorarnote is being checked
* the state machine offers nothing at all, and that is exactly when receipts must stay * the state machine offers nothing at all, and that is exactly when receipts must stay
* manageable. * manageable.
*
* @dataProvider receiptWindowStatuses
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('receiptWindowStatuses')]
public function testTheReceiptWindowIsTheTwoInvoiceStates(string $status, bool $expected): void public function testTheReceiptWindowIsTheTwoInvoiceStates(string $status, bool $expected): void
{ {
$this->security->method('isGranted')->willReturn(true); $this->security->method('isGranted')->willReturn(true);
@@ -139,9 +135,8 @@ class DispositionVoterTest extends TestCase
/** /**
* The owning teamer gets in without being administrative; anyone else's teamer does not. * The owning teamer gets in without being administrative; anyone else's teamer does not.
*
* @dataProvider receiptOwnership
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('receiptOwnership')]
public function testOnlyTheOwningTeamerMayManageTheirReceipts(bool $owning, bool $expected): void public function testOnlyTheOwningTeamerMayManageTheirReceipts(bool $owning, bool $expected): void
{ {
$this->security $this->security
@@ -158,7 +153,7 @@ class DispositionVoterTest extends TestCase
$user = (new User())->setTeamer($owning ? $teamer : new Teamer()); $user = (new User())->setTeamer($owning ? $teamer : new Teamer());
$token = $this->createMock(TokenInterface::class); $token = $this->createStub(TokenInterface::class);
$token->method('getUser')->willReturn($user); $token->method('getUser')->willReturn($user);
$this->assertSame( $this->assertSame(
@@ -181,7 +176,7 @@ class DispositionVoterTest extends TestCase
private function vote(string $attribute, Disposition $disposition): int private function vote(string $attribute, Disposition $disposition): int
{ {
return (new DispositionVoter($this->security))->vote( return (new DispositionVoter($this->security))->vote(
$this->createMock(TokenInterface::class), $this->createStub(TokenInterface::class),
$disposition, $disposition,
[$attribute], [$attribute],
); );
+5 -6
View File
@@ -9,7 +9,7 @@ use App\Entity\Teamer;
use App\Entity\Upload; use App\Entity\Upload;
use App\Entity\User; use App\Entity\User;
use App\Security\Voter\UploadVoter; use App\Security\Voter\UploadVoter;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@@ -22,11 +22,11 @@ use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
*/ */
class UploadVoterTest extends TestCase class UploadVoterTest extends TestCase
{ {
private Security&MockObject $security; private Security&Stub $security;
protected function setUp(): void protected function setUp(): void
{ {
$this->security = $this->createMock(Security::class); $this->security = $this->createStub(Security::class);
$this->security $this->security
->method('isGranted') ->method('isGranted')
->willReturnCallback(static fn (string $role): bool => 'ROLE_TEAMER' === $role) ->willReturnCallback(static fn (string $role): bool => 'ROLE_TEAMER' === $role)
@@ -68,9 +68,8 @@ class UploadVoterTest extends TestCase
/** /**
* Downloading is all the new rule grants: the file stays the office's, so the teamer it was * Downloading is all the new rule grants: the file stays the office's, so the teamer it was
* issued to may not delete it or reach it through any other attribute. * issued to may not delete it or reach it through any other attribute.
*
* @dataProvider otherAttributes
*/ */
#[\PHPUnit\Framework\Attributes\DataProvider('otherAttributes')]
public function testTheNewRuleGrantsNothingButDownloading(string $attribute): void public function testTheNewRuleGrantsNothingButDownloading(string $attribute): void
{ {
$teamer = new Teamer(); $teamer = new Teamer();
@@ -124,7 +123,7 @@ class UploadVoterTest extends TestCase
private function vote(string $attribute, Upload $upload, Teamer $teamer): int private function vote(string $attribute, Upload $upload, Teamer $teamer): int
{ {
$token = $this->createMock(TokenInterface::class); $token = $this->createStub(TokenInterface::class);
$token->method('getUser')->willReturn((new User())->setTeamer($teamer)); $token->method('getUser')->willReturn((new User())->setTeamer($teamer));
return (new UploadVoter($this->security))->vote($token, $upload, [$attribute]); return (new UploadVoter($this->security))->vote($token, $upload, [$attribute]);
+5 -6
View File
@@ -6,7 +6,7 @@ namespace App\Tests\Security\Voter;
use App\Entity\User; use App\Entity\User;
use App\Security\Voter\UserVoter; use App\Security\Voter\UserVoter;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@@ -14,11 +14,11 @@ use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
class UserVoterTest extends TestCase class UserVoterTest extends TestCase
{ {
private Security&MockObject $security; private Security&Stub $security;
protected function setUp(): void protected function setUp(): void
{ {
$this->security = $this->createMock(Security::class); $this->security = $this->createStub(Security::class);
} }
public function testSuperAdminMayEditOtherUsers(): void public function testSuperAdminMayEditOtherUsers(): void
@@ -59,10 +59,9 @@ class UserVoterTest extends TestCase
{ {
$this->security $this->security
->method('isGranted') ->method('isGranted')
->with('IS_IMPERSONATOR') ->willReturnCallback(static fn (mixed $attribute): bool => 'IS_IMPERSONATOR' === $attribute && $isImpersonator);
->willReturn($isImpersonator);
$token = $this->createMock(TokenInterface::class); $token = $this->createStub(TokenInterface::class);
$token $token
->method('getUser') ->method('getUser')
->willReturn($currentUser); ->willReturn($currentUser);
@@ -22,9 +22,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
*/ */
class AbstractFilterHandlerTest extends TestCase class AbstractFilterHandlerTest extends TestCase
{ {
/** #[\PHPUnit\Framework\Attributes\DataProvider('legacyCountries')]
* @dataProvider legacyCountries
*/
public function testALegacyCountryIsTranslatedToItsIsoCode(?string $stored, ?string $expected): void public function testALegacyCountryIsTranslatedToItsIsoCode(?string $stored, ?string $expected): void
{ {
$this->assertSame($expected, $this->handler()->translate($stored)); $this->assertSame($expected, $this->handler()->translate($stored));
@@ -67,7 +65,7 @@ class AbstractFilterHandlerTest extends TestCase
private function handler(): object private function handler(): object
{ {
return new class($this->createMock(RequestStack::class), $this->createMock(EntityManagerInterface::class)) extends AbstractFilterHandler { return new class($this->createStub(RequestStack::class), $this->createStub(EntityManagerInterface::class)) extends AbstractFilterHandler {
protected string $modelClass = AssignmentFilterDto::class; protected string $modelClass = AssignmentFilterDto::class;
public function translate(?string $country): ?string public function translate(?string $country): ?string
@@ -87,6 +87,6 @@ class TeamerFilterHandlerTest extends TestCase
$requestStack = new RequestStack(); $requestStack = new RequestStack();
$requestStack->push($request); $requestStack->push($request);
return new TeamerFilterHandler($requestStack, $this->createMock(EntityManagerInterface::class)); return new TeamerFilterHandler($requestStack, $this->createStub(EntityManagerInterface::class));
} }
} }
@@ -11,7 +11,7 @@ use App\Entity\Teamer;
use App\Repository\DispositionRepository; use App\Repository\DispositionRepository;
use App\Service\Cron\DispositionStatusService; use App\Service\Cron\DispositionStatusService;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@@ -24,14 +24,14 @@ use Psr\Log\NullLogger;
*/ */
class DispositionStatusServiceTest extends TestCase class DispositionStatusServiceTest extends TestCase
{ {
private DispositionRepository&MockObject $repository; private DispositionRepository&Stub $repository;
private DispositionStatusService $service; private DispositionStatusService $service;
protected function setUp(): void protected function setUp(): void
{ {
$this->repository = $this->createMock(DispositionRepository::class); $this->repository = $this->createStub(DispositionRepository::class);
$entityManager = $this->createMock(EntityManagerInterface::class); $entityManager = $this->createStub(EntityManagerInterface::class);
$entityManager $entityManager
->method('getRepository') ->method('getRepository')
->willReturn($this->repository) ->willReturn($this->repository)
@@ -17,6 +17,7 @@ use App\Repository\SeasonAssignmentTaskRepository;
use App\Service\Cron\SeasonTaskReminderService; use App\Service\Cron\SeasonTaskReminderService;
use App\Service\Season\SeasonAssignmentLabeler; use App\Service\Season\SeasonAssignmentLabeler;
use App\Service\Season\SeasonTaskDeadlineResolver; use App\Service\Season\SeasonTaskDeadlineResolver;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@@ -26,6 +27,7 @@ use Psr\Log\NullLogger;
* anyone twice. That property, and what does and does not silence a reminder, is what is pinned * anyone twice. That property, and what does and does not silence a reminder, is what is pinned
* here - the queries behind them are asserted in the repository test. * here - the queries behind them are asserted in the repository test.
*/ */
#[AllowMockObjectsWithoutExpectations]
class SeasonTaskReminderServiceTest extends TestCase class SeasonTaskReminderServiceTest extends TestCase
{ {
private SeasonAssignmentTaskRepository&MockObject $repository; private SeasonAssignmentTaskRepository&MockObject $repository;
@@ -14,6 +14,7 @@ use App\Entity\Embeddable\Communication;
use App\Entity\Teamer; use App\Entity\Teamer;
use App\Repository\DispositionRepository; use App\Repository\DispositionRepository;
use App\Service\Cron\UploadReminderService; use App\Service\Cron\UploadReminderService;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@@ -25,6 +26,7 @@ use Psr\Log\NullLogger;
* arithmetic the service hands over, because a reminder that asks for the wrong day is just as * arithmetic the service hands over, because a reminder that asks for the wrong day is just as
* silent as the broken queries these replaced. * silent as the broken queries these replaced.
*/ */
#[AllowMockObjectsWithoutExpectations]
class UploadReminderServiceTest extends TestCase class UploadReminderServiceTest extends TestCase
{ {
private const CONTRACT_DEADLINE_DAYS = 5; private const CONTRACT_DEADLINE_DAYS = 5;
@@ -11,6 +11,7 @@ use App\Entity\Teamer;
use App\Entity\TeamerWorkMonth; use App\Entity\TeamerWorkMonth;
use App\Repository\TeamerWorkMonthRepository; use App\Repository\TeamerWorkMonthRepository;
use App\Service\Cron\WorkMonthReminderService; use App\Service\Cron\WorkMonthReminderService;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@@ -19,6 +20,7 @@ use Psr\Log\NullLogger;
* Pins the rules the reminder applies: which day it runs on, how long it waits after an * Pins the rules the reminder applies: which day it runs on, how long it waits after an
* import, and who it can actually reach. The query itself is the repository's business. * import, and who it can actually reach. The query itself is the repository's business.
*/ */
#[AllowMockObjectsWithoutExpectations]
class WorkMonthReminderServiceTest extends TestCase class WorkMonthReminderServiceTest extends TestCase
{ {
private TeamerWorkMonthRepository&MockObject $repository; private TeamerWorkMonthRepository&MockObject $repository;
+8 -11
View File
@@ -12,10 +12,9 @@ use App\Entity\JobProfile;
use App\Entity\Teamer; use App\Entity\Teamer;
use App\Entity\Upload; use App\Entity\Upload;
use App\Service\Pdf\InvoiceApprover; use App\Service\Pdf\InvoiceApprover;
use App\Service\Pdf\InvoiceRenderer;
use App\Service\Pdf\Pdf; use App\Service\Pdf\Pdf;
use App\Service\Upload\UploadHandler; use App\Service\Upload\UploadHandler;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Stub;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
@@ -27,7 +26,7 @@ class InvoiceApproverTest extends WebTestCase
private string $pdfPath; private string $pdfPath;
private string $origPath; private string $origPath;
private Filesystem $filesystem; private Filesystem $filesystem;
private UploadHandler&MockObject $uploadHandler; private UploadHandler&Stub $uploadHandler;
protected function setUp(): void protected function setUp(): void
{ {
@@ -38,7 +37,7 @@ class InvoiceApproverTest extends WebTestCase
$this->pdfPath = $this->invoiceDir.'/test_approver_backup.pdf'; $this->pdfPath = $this->invoiceDir.'/test_approver_backup.pdf';
$this->origPath = $this->invoiceDir.'/test_approver_backup.orig.pdf'; $this->origPath = $this->invoiceDir.'/test_approver_backup.orig.pdf';
$this->filesystem = new Filesystem(); $this->filesystem = new Filesystem();
$this->uploadHandler = $this->createMock(UploadHandler::class); $this->uploadHandler = $this->createStub(UploadHandler::class);
$this->filesystem->mkdir($this->invoiceDir); $this->filesystem->mkdir($this->invoiceDir);
} }
@@ -81,10 +80,7 @@ class InvoiceApproverTest extends WebTestCase
private function createApprover(): InvoiceApprover private function createApprover(): InvoiceApprover
{ {
$translator = $this->createMock(TranslatorInterface::class); return new InvoiceApprover($this->createStub(TranslatorInterface::class), ['project_dir' => $this->projectDir], $this->uploadHandler);
/** @var TranslatorInterface $translator */
return new InvoiceApprover($translator, ['project_dir' => $this->projectDir], $this->uploadHandler);
} }
private function createDispositionWithInvoicePdf(): Disposition private function createDispositionWithInvoicePdf(): Disposition
@@ -109,7 +105,7 @@ class InvoiceApproverTest extends WebTestCase
$jobProfile->setName('Testprofil'); $jobProfile->setName('Testprofil');
$jobProfile->setCostUnit('200'); $jobProfile->setCostUnit('200');
$assignment = $this->createMock(Assignment::class); $assignment = $this->createStub(Assignment::class);
$assignment->method('getDestination')->willReturn($destination); $assignment->method('getDestination')->willReturn($destination);
$assignment->method('getJobProfile')->willReturn($jobProfile); $assignment->method('getJobProfile')->willReturn($jobProfile);
@@ -134,8 +130,9 @@ class InvoiceApproverTest extends WebTestCase
; ;
$disposition->addDocument($invoice); $disposition->addDocument($invoice);
$this->uploadHandler->method('getResolvedUploadFilepath')->with($invoice)->willReturn($this->pdfPath); $filepath = fn (Upload $upload): string => $invoice === $upload ? $this->pdfPath : throw new \LogicException('Unexpected upload');
$this->uploadHandler->method('getUploadFilepath')->with($invoice)->willReturn($this->pdfPath); $this->uploadHandler->method('getResolvedUploadFilepath')->willReturnCallback($filepath);
$this->uploadHandler->method('getUploadFilepath')->willReturnCallback($filepath);
return $disposition; return $disposition;
} }
+6 -5
View File
@@ -25,7 +25,7 @@ class InvoiceRendererTest extends WebTestCase
public function testRendersInvoice(): void public function testRendersInvoice(): void
{ {
$projectDir = static::getContainer()->getParameter('kernel.project_dir'); $projectDir = static::getContainer()->getParameter('kernel.project_dir');
$translator = $this->createMock(TranslatorInterface::class); $translator = $this->createStub(TranslatorInterface::class);
/** @var TranslatorInterface $translator */ /** @var TranslatorInterface $translator */
$renderer = new InvoiceRenderer($translator, ['project_dir' => $projectDir]); $renderer = new InvoiceRenderer($translator, ['project_dir' => $projectDir]);
@@ -82,7 +82,7 @@ class InvoiceRendererTest extends WebTestCase
->setEmail('[email protected]') ->setEmail('[email protected]')
; ;
$assignment = $this->createMock(Assignment::class); $assignment = $this->createStub(Assignment::class);
$assignment->method('getId')->willReturn(1234); $assignment->method('getId')->willReturn(1234);
$assignment->method('getDestination')->willReturn($destination); $assignment->method('getDestination')->willReturn($destination);
$assignment->method('getJobProfile')->willReturn($jobProfile); $assignment->method('getJobProfile')->willReturn($jobProfile);
@@ -108,9 +108,10 @@ class InvoiceRendererTest extends WebTestCase
$disposition->addDocument($invoice); $disposition->addDocument($invoice);
$invoicePath = $projectDir.'/uploads/invoice/a/abcdef0123456789.pdf'; $invoicePath = $projectDir.'/uploads/invoice/a/abcdef0123456789.pdf';
$uploadHandler = $this->createMock(UploadHandler::class); $uploadHandler = $this->createStub(UploadHandler::class);
$uploadHandler->method('getResolvedUploadFilepath')->with($invoice)->willReturn($invoicePath); $filepath = static fn (Upload $upload): string => $invoice === $upload ? $invoicePath : throw new \LogicException('Unexpected upload');
$uploadHandler->method('getUploadFilepath')->with($invoice)->willReturn($invoicePath); $uploadHandler->method('getResolvedUploadFilepath')->willReturnCallback($filepath);
$uploadHandler->method('getUploadFilepath')->willReturnCallback($filepath);
/** @var TranslatorInterface $translator */ /** @var TranslatorInterface $translator */
$approver = new InvoiceApprover($translator, ['project_dir' => $projectDir], $uploadHandler); $approver = new InvoiceApprover($translator, ['project_dir' => $projectDir], $uploadHandler);
@@ -18,24 +18,27 @@ use App\Saas\Model\EmployeeDirectory;
use App\Saas\ResponseParser; use App\Saas\ResponseParser;
use App\Service\Saas\WorkHoursSynchronizer; use App\Service\Saas\WorkHoursSynchronizer;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
#[AllowMockObjectsWithoutExpectations]
class WorkHoursSynchronizerTest extends TestCase class WorkHoursSynchronizerTest extends TestCase
{ {
private ApiClient&MockObject $apiClient; private ApiClient&MockObject $apiClient;
private EmployeeDataProvider&MockObject $employeeDataProvider; private EmployeeDataProvider&Stub $employeeDataProvider;
private TeamerWorkMonthRepository&MockObject $workMonthRepository; private TeamerWorkMonthRepository&Stub $workMonthRepository;
private EntityManagerInterface&MockObject $entityManager; private EntityManagerInterface&MockObject $entityManager;
private WorkHoursSynchronizer $synchronizer; private WorkHoursSynchronizer $synchronizer;
protected function setUp(): void protected function setUp(): void
{ {
$this->apiClient = $this->createMock(ApiClient::class); $this->apiClient = $this->createMock(ApiClient::class);
$this->workMonthRepository = $this->createMock(TeamerWorkMonthRepository::class); $this->workMonthRepository = $this->createStub(TeamerWorkMonthRepository::class);
$this->entityManager = $this->createMock(EntityManagerInterface::class); $this->entityManager = $this->createMock(EntityManagerInterface::class);
$this->employeeDataProvider = $this->createMock(EmployeeDataProvider::class); $this->employeeDataProvider = $this->createStub(EmployeeDataProvider::class);
// Registered by default; the tests that care say otherwise. // Registered by default; the tests that care say otherwise.
$this->employeeDataProvider->method('getDirectory')->willReturn( $this->employeeDataProvider->method('getDirectory')->willReturn(
@@ -48,7 +51,7 @@ class WorkHoursSynchronizerTest extends TestCase
$this->apiClient, $this->apiClient,
new ResponseParser(), new ResponseParser(),
$this->employeeDataProvider, $this->employeeDataProvider,
$this->createMock(TeamerRepository::class), $this->createStub(TeamerRepository::class),
$this->workMonthRepository, $this->workMonthRepository,
$this->entityManager, $this->entityManager,
new NullLogger(), new NullLogger(),
@@ -85,7 +88,7 @@ class WorkHoursSynchronizerTest extends TestCase
*/ */
public function testATeamerMissingFromTheRosterIsSkippedWithoutAnyRequest(): void public function testATeamerMissingFromTheRosterIsSkippedWithoutAnyRequest(): void
{ {
$provider = $this->createMock(EmployeeDataProvider::class); $provider = $this->createStub(EmployeeDataProvider::class);
$provider->method('getDirectory')->willReturn( $provider->method('getDirectory')->willReturn(
EmployeeDirectory::fromEmployees([new Employee('[email protected]', 'e-9', 'Service', false)]) EmployeeDirectory::fromEmployees([new Employee('[email protected]', 'e-9', 'Service', false)])
); );
@@ -97,7 +100,7 @@ class WorkHoursSynchronizerTest extends TestCase
$apiClient, $apiClient,
new ResponseParser(), new ResponseParser(),
$provider, $provider,
$this->createMock(TeamerRepository::class), $this->createStub(TeamerRepository::class),
$this->workMonthRepository, $this->workMonthRepository,
$this->entityManager, $this->entityManager,
new NullLogger(), new NullLogger(),
@@ -115,7 +118,7 @@ class WorkHoursSynchronizerTest extends TestCase
*/ */
public function testAnUnreachableRosterDoesNotSkipEveryone(): void public function testAnUnreachableRosterDoesNotSkipEveryone(): void
{ {
$provider = $this->createMock(EmployeeDataProvider::class); $provider = $this->createStub(EmployeeDataProvider::class);
$provider->method('getDirectory')->willReturn(EmployeeDirectory::fromEmployees([])); $provider->method('getDirectory')->willReturn(EmployeeDirectory::fromEmployees([]));
$this->apiClient->method('getTimeAccount')->willReturn($this->payload()); $this->apiClient->method('getTimeAccount')->willReturn($this->payload());
@@ -125,7 +128,7 @@ class WorkHoursSynchronizerTest extends TestCase
$this->apiClient, $this->apiClient,
new ResponseParser(), new ResponseParser(),
$provider, $provider,
$this->createMock(TeamerRepository::class), $this->createStub(TeamerRepository::class),
$this->workMonthRepository, $this->workMonthRepository,
$this->entityManager, $this->entityManager,
new NullLogger(), new NullLogger(),
@@ -29,7 +29,7 @@ class SeasonChecklistBuilderTest extends TestCase
->setDocument($document) ->setDocument($document)
); );
$builder = new SeasonChecklistBuilder($this->createMock(SeasonTaskDeadlineResolver::class)); $builder = new SeasonChecklistBuilder($this->createStub(SeasonTaskDeadlineResolver::class));
$rows = $builder->build($seasonAssignment); $rows = $builder->build($seasonAssignment);
@@ -44,7 +44,7 @@ class SeasonChecklistBuilderTest extends TestCase
(new SeasonAssignmentTask())->setTaskKey(SeasonTask::MASTER_DATA->value) (new SeasonAssignmentTask())->setTaskKey(SeasonTask::MASTER_DATA->value)
); );
$builder = new SeasonChecklistBuilder($this->createMock(SeasonTaskDeadlineResolver::class)); $builder = new SeasonChecklistBuilder($this->createStub(SeasonTaskDeadlineResolver::class));
$rows = $builder->build($seasonAssignment); $rows = $builder->build($seasonAssignment);
@@ -22,7 +22,7 @@ class SeasonChecklistStatusTest extends TestCase
protected function setUp(): void protected function setUp(): void
{ {
$this->builder = new SeasonChecklistBuilder($this->createMock(SeasonTaskDeadlineResolver::class)); $this->builder = new SeasonChecklistBuilder($this->createStub(SeasonTaskDeadlineResolver::class));
} }
public function testItIsOpenWhileAnEntryRequiringAReturnIsOpen(): void public function testItIsOpenWhileAnEntryRequiringAReturnIsOpen(): void
@@ -12,7 +12,9 @@ use App\Entity\Upload;
use App\Repository\SeasonTaskDocumentRepository; use App\Repository\SeasonTaskDocumentRepository;
use App\Service\Season\SeasonTaskSynchronizer; use App\Service\Season\SeasonTaskSynchronizer;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
/** /**
@@ -20,16 +22,17 @@ use PHPUnit\Framework\TestCase;
* that is what is asserted: new entries appear on assignments that already exist, and rows of * that is what is asserted: new entries appear on assignments that already exist, and rows of
* an entry that was removed are left alone rather than deleted. * an entry that was removed are left alone rather than deleted.
*/ */
#[AllowMockObjectsWithoutExpectations]
class SeasonTaskSynchronizerTest extends TestCase class SeasonTaskSynchronizerTest extends TestCase
{ {
private EntityManagerInterface&MockObject $entityManager; private EntityManagerInterface&MockObject $entityManager;
private SeasonTaskDocumentRepository&MockObject $seasonTaskDocumentRepository; private SeasonTaskDocumentRepository&Stub $seasonTaskDocumentRepository;
private SeasonTaskSynchronizer $synchronizer; private SeasonTaskSynchronizer $synchronizer;
protected function setUp(): void protected function setUp(): void
{ {
$this->entityManager = $this->createMock(EntityManagerInterface::class); $this->entityManager = $this->createMock(EntityManagerInterface::class);
$this->seasonTaskDocumentRepository = $this->createMock(SeasonTaskDocumentRepository::class); $this->seasonTaskDocumentRepository = $this->createStub(SeasonTaskDocumentRepository::class);
$this->synchronizer = new SeasonTaskSynchronizer( $this->synchronizer = new SeasonTaskSynchronizer(
$this->entityManager, $this->entityManager,
@@ -12,21 +12,24 @@ use App\Enum\StatisticsEventName;
use App\Service\Statistics\StatisticsRecorder; use App\Service\Statistics\StatisticsRecorder;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\DatabaseRequired; use Doctrine\DBAL\Exception\DatabaseRequired;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
#[AllowMockObjectsWithoutExpectations]
class StatisticsRecorderTest extends TestCase class StatisticsRecorderTest extends TestCase
{ {
private Connection&MockObject $connection; private Connection&MockObject $connection;
private Security&MockObject $security; private Security&Stub $security;
private LoggerInterface&MockObject $logger; private LoggerInterface&MockObject $logger;
protected function setUp(): void protected function setUp(): void
{ {
$this->connection = $this->createMock(Connection::class); $this->connection = $this->createMock(Connection::class);
$this->security = $this->createMock(Security::class); $this->security = $this->createStub(Security::class);
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
@@ -8,10 +8,12 @@ use App\Entity\Teamer;
use App\Entity\User; use App\Entity\User;
use App\Service\Teamer\AccountDeletionHandler; use App\Service\Teamer\AccountDeletionHandler;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
#[AllowMockObjectsWithoutExpectations]
class AccountDeletionHandlerTest extends TestCase class AccountDeletionHandlerTest extends TestCase
{ {
private EntityManagerInterface&MockObject $entityManager; private EntityManagerInterface&MockObject $entityManager;
@@ -23,7 +25,7 @@ class AccountDeletionHandlerTest extends TestCase
$this->handler = new AccountDeletionHandler( $this->handler = new AccountDeletionHandler(
$this->entityManager, $this->entityManager,
$this->createMock(LoggerInterface::class), $this->createStub(LoggerInterface::class),
); );
} }
@@ -8,17 +8,17 @@ use App\Config\SeasonCalendar;
use App\Entity\Teamer; use App\Entity\Teamer;
use App\Repository\DispositionRepository; use App\Repository\DispositionRepository;
use App\Service\Teamer\SeasonDispositionCounter; use App\Service\Teamer\SeasonDispositionCounter;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class SeasonDispositionCounterTest extends TestCase class SeasonDispositionCounterTest extends TestCase
{ {
private DispositionRepository&MockObject $dispositionRepository; private DispositionRepository&Stub $dispositionRepository;
private SeasonDispositionCounter $counter; private SeasonDispositionCounter $counter;
protected function setUp(): void protected function setUp(): void
{ {
$this->dispositionRepository = $this->createMock(DispositionRepository::class); $this->dispositionRepository = $this->createStub(DispositionRepository::class);
$this->counter = new SeasonDispositionCounter( $this->counter = new SeasonDispositionCounter(
$this->dispositionRepository, $this->dispositionRepository,
@@ -15,20 +15,23 @@ use App\Model\TeamerMailingRecipient;
use App\Model\TeamerMailingRecipientsDto; use App\Model\TeamerMailingRecipientsDto;
use App\Repository\TeamerRepository; use App\Repository\TeamerRepository;
use App\Service\Teamer\TeamerMailingService; use App\Service\Teamer\TeamerMailingService;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
#[AllowMockObjectsWithoutExpectations]
class TeamerMailingServiceTest extends TestCase class TeamerMailingServiceTest extends TestCase
{ {
private TeamerRepository&MockObject $teamerRepository; private TeamerRepository&Stub $teamerRepository;
private Mailer&MockObject $mailer; private Mailer&MockObject $mailer;
private TeamerMailingService $service; private TeamerMailingService $service;
private static int $nextId = 1; private static int $nextId = 1;
protected function setUp(): void protected function setUp(): void
{ {
$this->teamerRepository = $this->createMock(TeamerRepository::class); $this->teamerRepository = $this->createStub(TeamerRepository::class);
$this->mailer = $this->createMock(Mailer::class); $this->mailer = $this->createMock(Mailer::class);
// The real renderer, not a mock: what the mailing puts in front of a teamer is // The real renderer, not a mock: what the mailing puts in front of a teamer is
@@ -37,7 +40,7 @@ class TeamerMailingServiceTest extends TestCase
$this->teamerRepository, $this->teamerRepository,
$this->mailer, $this->mailer,
new MailBodyRenderer(), new MailBodyRenderer(),
$this->createMock(LoggerInterface::class), $this->createStub(LoggerInterface::class),
'mailing', 'mailing',
); );
} }
@@ -17,6 +17,7 @@ use App\Entity\User;
use App\Service\Teamer\TeamerProvisioner; use App\Service\Teamer\TeamerProvisioner;
use App\Service\Teamer\TeamerProvisioningException; use App\Service\Teamer\TeamerProvisioningException;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@@ -28,6 +29,7 @@ use Psr\Log\NullLogger;
* client: what runs, in which order, what is persisted before the next step, and what a retry does * client: what runs, in which order, what is persisted before the next step, and what a retry does
* after a failure halfway. * after a failure halfway.
*/ */
#[AllowMockObjectsWithoutExpectations]
class TeamerProvisionerTest extends TestCase class TeamerProvisionerTest extends TestCase
{ {
private const SELECTION_ID = 1070; private const SELECTION_ID = 1070;
@@ -366,7 +368,7 @@ class TeamerProvisionerTest extends TestCase
return new TeamerProvisioner( return new TeamerProvisioner(
$this->apiClient, $this->apiClient,
$this->userDataHandler, $this->userDataHandler,
$this->createMock(EntityManagerInterface::class), $this->createStub(EntityManagerInterface::class),
new NullLogger(), new NullLogger(),
self::SELECTION_ID, self::SELECTION_ID,
); );
+3 -3
View File
@@ -110,9 +110,9 @@ class UploadHandlerTest extends TestCase
private function handler(string $replacementFile = self::REPLACEMENT_FILE): UploadHandler private function handler(string $replacementFile = self::REPLACEMENT_FILE): UploadHandler
{ {
return new UploadHandler( return new UploadHandler(
$this->createMock(RequestStack::class), $this->createStub(RequestStack::class),
$this->createMock(OrphanageManager::class), $this->createStub(OrphanageManager::class),
$this->createMock(Sanitizer::class), $this->createStub(Sanitizer::class),
new NullLogger(), new NullLogger(),
$this->featureManager, $this->featureManager,
$this->projectDir, $this->projectDir,
@@ -84,7 +84,7 @@ class ResolvableHotelValidatorTest extends ConstraintValidatorTestCase
*/ */
private function provider(array $hotels): object private function provider(array $hotels): object
{ {
$provider = $this->createMock(HotelDataProvider::class); $provider = $this->createStub(HotelDataProvider::class);
$provider->method('getAll')->willReturn($hotels); $provider->method('getAll')->willReturn($hotels);
return $provider; return $provider;
@@ -10,6 +10,7 @@ use App\Entity\Teamer;
use App\Repository\SeasonAssignmentRepository; use App\Repository\SeasonAssignmentRepository;
use App\Validator\Constraints\SeasonAssignment as SeasonAssignmentConstraint; use App\Validator\Constraints\SeasonAssignment as SeasonAssignmentConstraint;
use App\Validator\Constraints\SeasonAssignmentValidator; use App\Validator\Constraints\SeasonAssignmentValidator;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
@@ -18,6 +19,7 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
* pinned here is which season window a given assignment is counted against, and the cases that * pinned here is which season window a given assignment is counted against, and the cases that
* must not be refused - an unstaffed assignment, and the assignment being edited itself. * must not be refused - an unstaffed assignment, and the assignment being edited itself.
*/ */
#[AllowMockObjectsWithoutExpectations]
class SeasonAssignmentValidatorTest extends ConstraintValidatorTestCase class SeasonAssignmentValidatorTest extends ConstraintValidatorTestCase
{ {
private SeasonAssignmentRepository&MockObject $repository; private SeasonAssignmentRepository&MockObject $repository;