Quellcode durchsuchen

complete unit tests

Olivier Massot vor 3 Monaten
Ursprung
Commit
e4802cfa85

+ 7 - 7
src/Service/ApiResourceBuilder/Freemium/EventMappingBuilder.php

@@ -28,8 +28,8 @@ class EventMappingBuilder
      */
     public function mapInformations(Event $event, FreemiumEvent $freemiumEvent): void
     {
-        $this->mapEventInformations( $event, $freemiumEvent);
-        $this->mapEventPlaceInformations( $event, $freemiumEvent);
+        $this->mapEventInformations($event, $freemiumEvent);
+        $this->mapEventPlaceInformations($event, $freemiumEvent);
     }
 
     /**
@@ -38,7 +38,7 @@ class EventMappingBuilder
      * @param Event $event : objet target
      * @param FreemiumEvent $freemiumEvent : objet source
      */
-    private function mapEventInformations(Event $event, FreemiumEvent $freemiumEvent): void
+    protected function mapEventInformations(Event $event, FreemiumEvent $freemiumEvent): void
     {
         //General informations
         $event->setName($freemiumEvent->name);
@@ -65,7 +65,7 @@ class EventMappingBuilder
      * @param Event $event
      * @param FreemiumEvent $freemiumEvent
      */
-    private function mapEventPlaceInformations(Event $event, FreemiumEvent $freemiumEvent): void
+    protected function mapEventPlaceInformations(Event $event, FreemiumEvent $freemiumEvent): void
     {
         $place = $this->getPlace($freemiumEvent);
         if($place !== null){
@@ -80,7 +80,7 @@ class EventMappingBuilder
      * @param Place $place
      * @param FreemiumEvent $freemiumEvent
      */
-    private function mapPlaceInformations(Place $place, FreemiumEvent $freemiumEvent): void
+    protected function mapPlaceInformations(Place $place, FreemiumEvent $freemiumEvent): void
     {
         $addressPostal = $this->getAddressPostal($place);
 
@@ -107,7 +107,7 @@ class EventMappingBuilder
      * @param FreemiumEvent $freemiumEvent
      * @return Place|null
      */
-    private function getPlace(FreemiumEvent $freemiumEvent): ?Place
+    protected function getPlace(FreemiumEvent $freemiumEvent): ?Place
     {
         if ($freemiumEvent->place) {
             return $freemiumEvent->place;
@@ -129,7 +129,7 @@ class EventMappingBuilder
      * @param Place $place
      * @return AddressPostal
      */
-    private function getAddressPostal(Place $place): AddressPostal
+    protected function getAddressPostal(Place $place): AddressPostal
     {
         if ($place->getAddressPostal()) {
             return $place->getAddressPostal();

+ 5 - 5
src/Service/ApiResourceBuilder/Freemium/OrganizationMappingBuilder.php

@@ -41,7 +41,7 @@ class OrganizationMappingBuilder
      * @param Organization         $organization         : objet target
      * @param FreemiumOrganization $freemiumOrganization : objet source
      */
-    private function mapOrganizationInformations(Organization $organization, FreemiumOrganization $freemiumOrganization): void
+    protected function mapOrganizationInformations(Organization $organization, FreemiumOrganization $freemiumOrganization): void
     {
         $organization->setName($freemiumOrganization->name);
         $organization->setDescription($freemiumOrganization->description);
@@ -59,7 +59,7 @@ class OrganizationMappingBuilder
      * @param ContactPoint         $contactPoint         : objet target
      * @param FreemiumOrganization $freemiumOrganization : objet source
      */
-    private function mapContactPointInformations(ContactPoint $contactPoint, FreemiumOrganization $freemiumOrganization): void
+    protected function mapContactPointInformations(ContactPoint $contactPoint, FreemiumOrganization $freemiumOrganization): void
     {
         $contactPoint->setTelphone($freemiumOrganization->tel);
         $contactPoint->setEmail($freemiumOrganization->email);
@@ -71,7 +71,7 @@ class OrganizationMappingBuilder
      * @param AddressPostal        $address              : objet target
      * @param FreemiumOrganization $freemiumOrganization : objet source
      */
-    private function mapAddressPostalInformations(AddressPostal $address, FreemiumOrganization $freemiumOrganization): void
+    protected function mapAddressPostalInformations(AddressPostal $address, FreemiumOrganization $freemiumOrganization): void
     {
         $address->setStreetAddress($freemiumOrganization->streetAddress);
         $address->setStreetAddressSecond($freemiumOrganization->streetAddressSecond);
@@ -86,7 +86,7 @@ class OrganizationMappingBuilder
     /**
      * On récupère le point de contact principal de l'organisation. Si elle n'existe pas on l'à créer.
      */
-    private function getPrincipalContactPointOrCreateNewOne(Organization $organization): ContactPoint
+    protected function getPrincipalContactPointOrCreateNewOne(Organization $organization): ContactPoint
     {
         $principalContactPoint = $organization->getPrincipalContactPoint();
         if ($principalContactPoint) {
@@ -103,7 +103,7 @@ class OrganizationMappingBuilder
     /**
      * On récupère l'adresse principale de l'organisation. Si elle n'existe pas on l'à créer.
      */
-    private function getPrincipalAddressPostalOrCreateNewOne(Organization $organization): AddressPostal
+    protected function getPrincipalAddressPostalOrCreateNewOne(Organization $organization): AddressPostal
     {
         $principalAddressPostal = $organization->getPrincipalAddressPostal();
         if ($principalAddressPostal) {

+ 298 - 0
tests/Unit/Service/ApiResourceBuilder/Freemium/EventMappingBuilderTest.php

@@ -0,0 +1,298 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Tests\Unit\Service\ApiResourceBuilder\Freemium;
+
+use App\ApiResources\Freemium\FreemiumEvent;
+use App\Entity\Booking\Event;
+use App\Entity\Core\AddressPostal;
+use App\Entity\Core\Categories;
+use App\Entity\Core\Country;
+use App\Entity\Core\File;
+use App\Entity\Organization\Organization;
+use App\Entity\Place\Place;
+use App\Service\ApiResourceBuilder\Freemium\EventMappingBuilder;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class TestableEventMappingBuilder extends EventMappingBuilder
+{
+    public function mapEventInformations(Event $event, FreemiumEvent $freemiumEvent): void
+    {
+        parent::mapEventInformations($event, $freemiumEvent);
+    }
+
+    public function mapEventPlaceInformations(Event $event, FreemiumEvent $freemiumEvent): void
+    {
+        parent::mapEventPlaceInformations($event, $freemiumEvent);
+    }
+
+    public function mapPlaceInformations(Place $place, FreemiumEvent $freemiumEvent): void
+    {
+        parent::mapPlaceInformations($place, $freemiumEvent);
+    }
+
+    public function getPlace(FreemiumEvent $freemiumEvent): ?Place
+    {
+        return parent::getPlace($freemiumEvent);
+    }
+
+    public function getAddressPostal(Place $place): AddressPostal
+    {
+        return parent::getAddressPostal($place);
+    }
+}
+
+class EventMappingBuilderTest extends TestCase
+{
+    private EntityManagerInterface|MockObject $entityManager;
+
+    public function setUp(): void {
+        $this->entityManager = $this->createMock(EntityManagerInterface::class);
+    }
+
+    private function getEventMappingBuilderMockForMethod(string $methodName): TestableEventMappingBuilder|MockObject
+    {
+        return $this
+            ->getMockBuilder(TestableEventMappingBuilder::class)
+            ->setConstructorArgs([$this->entityManager])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
+    }
+
+    public function testMapInformations(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('mapInformations');
+
+        $event = $this->createMock(Event::class);
+        $freemiumEvent = $this->createMock(FreemiumEvent::class);
+
+        $eventMappingBuilder
+            ->expects($this->once())
+            ->method('mapEventInformations')
+            ->with($event, $freemiumEvent);
+
+        $eventMappingBuilder
+            ->expects($this->once())
+            ->method('mapEventPlaceInformations')
+            ->with($event, $freemiumEvent);
+
+        $eventMappingBuilder->mapInformations($event, $freemiumEvent);
+    }
+
+    public function testMapEventInformations(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('mapEventInformations');
+
+        $event = $this->createMock(Event::class);
+        $organization = $this->createMock(Organization::class);
+        $image = $this->createMock(File::class);
+        $category1 = $this->createMock(Categories::class);
+        $category2 = $this->createMock(Categories::class);
+
+        $freemiumEvent = new FreemiumEvent();
+        $freemiumEvent->name = 'Test Event';
+        $freemiumEvent->organization = $organization;
+        $freemiumEvent->datetimeStart = new \DateTime('2024-01-01 20:00:00');
+        $freemiumEvent->datetimeEnd = new \DateTime('2024-01-01 22:00:00');
+        $freemiumEvent->description = 'Test description';
+        $freemiumEvent->image = $image;
+        $freemiumEvent->url = 'https://example.com';
+        $freemiumEvent->urlTicket = 'https://tickets.example.com';
+        $freemiumEvent->pricing = null;
+        $freemiumEvent->priceMini = 0.0;
+        $freemiumEvent->priceMaxi = 50.0;
+        $freemiumEvent->addCategory($category1);
+        $freemiumEvent->addCategory($category2);
+
+        $event->expects($this->once())->method('setName')->with('Test Event');
+        $event->expects($this->once())->method('setOrganization')->with($organization);
+        $event->expects($this->once())->method('setDatetimeStart')->with(new \DateTime('2024-01-01 20:00:00'));
+        $event->expects($this->once())->method('setDatetimeEnd')->with(new \DateTime('2024-01-01 22:00:00'));
+        $event->expects($this->once())->method('setDescription')->with('Test description');
+        $event->expects($this->once())->method('setImage')->with($image);
+        $event->expects($this->once())->method('setUrl')->with('https://example.com');
+        $event->expects($this->once())->method('setUrlTicket')->with('https://tickets.example.com');
+        $event->expects($this->once())->method('setPricing')->with(null);
+        $event->expects($this->once())->method('setPriceMini')->with(0.0);
+        $event->expects($this->once())->method('setPriceMaxi')->with(50.0);
+        $event->expects($this->once())->method('removeAllCategories');
+        $event->expects($this->exactly(2))->method('addCategory');
+
+        $eventMappingBuilder->mapEventInformations($event, $freemiumEvent);
+    }
+
+    public function testMapEventPlaceInformations(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('mapEventPlaceInformations');
+
+        $event = $this->createMock(Event::class);
+        $freemiumEvent = $this->createMock(FreemiumEvent::class);
+        $place = $this->createMock(Place::class);
+
+        $eventMappingBuilder
+            ->expects($this->once())
+            ->method('getPlace')
+            ->with($freemiumEvent)
+            ->willReturn($place);
+
+        $eventMappingBuilder
+            ->expects($this->once())
+            ->method('mapPlaceInformations')
+            ->with($place, $freemiumEvent);
+
+        $this->entityManager
+            ->expects($this->once())
+            ->method('persist')
+            ->with($place);
+
+        $event->expects($this->once())->method('setPlace')->with($place);
+
+        $eventMappingBuilder->mapEventPlaceInformations($event, $freemiumEvent);
+    }
+
+    public function testMapEventPlaceInformationsWithNullPlace(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('mapEventPlaceInformations');
+
+        $event = $this->createMock(Event::class);
+        $freemiumEvent = $this->createMock(FreemiumEvent::class);
+
+        $eventMappingBuilder
+            ->expects($this->once())
+            ->method('getPlace')
+            ->with($freemiumEvent)
+            ->willReturn(null);
+
+        $eventMappingBuilder
+            ->expects($this->never())
+            ->method('mapPlaceInformations');
+
+        $this->entityManager
+            ->expects($this->never())
+            ->method('persist');
+
+        $event->expects($this->once())
+            ->method('setPlace')
+            ->with(null);
+
+        $eventMappingBuilder->mapEventPlaceInformations($event, $freemiumEvent);
+    }
+
+    public function testMapPlaceInformations(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('mapPlaceInformations');
+
+        $place = $this->createMock(Place::class);
+        $addressPostal = $this->createMock(AddressPostal::class);
+        $organization = $this->createMock(Organization::class);
+        $country = $this->createMock(Country::class);
+
+        $freemiumEvent = new FreemiumEvent();
+        $freemiumEvent->organization = $organization;
+        $freemiumEvent->placeName = 'Test Venue';
+        $freemiumEvent->streetAddress = '123 Test Street';
+        $freemiumEvent->streetAddressSecond = 'Apt 1';
+        $freemiumEvent->streetAddressThird = 'Floor 2';
+        $freemiumEvent->postalCode = '12345';
+        $freemiumEvent->addressCity = 'Test City';
+        $freemiumEvent->addressCountry = $country;
+        $freemiumEvent->latitude = 48.8566;
+        $freemiumEvent->longitude = 2.3522;
+
+        $eventMappingBuilder
+            ->expects($this->once())
+            ->method('getAddressPostal')
+            ->with($place)
+            ->willReturn($addressPostal);
+
+        // Verify address postal setters
+        $addressPostal->expects($this->once())->method('setStreetAddress')->with('123 Test Street')->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setStreetAddressSecond')->with('Apt 1')->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setStreetAddressThird')->with('Floor 2')->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setPostalCode')->with('12345')->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setAddressCity')->with('Test City')->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setAddressCountry')->with($country)->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setLatitude')->with(48.8566)->willReturn($addressPostal);
+        $addressPostal->expects($this->once())->method('setLongitude')->with(2.3522)->willReturn($addressPostal);
+
+        // Verify place setters
+        $place->expects($this->once())->method('setOrganization')->with($organization)->willReturn($place);
+        $place->expects($this->once())->method('setName')->with('Test Venue')->willReturn($place);
+        $place->expects($this->once())->method('setAddressPostal')->with($addressPostal)->willReturn($place);
+
+        $eventMappingBuilder->mapPlaceInformations($place, $freemiumEvent);
+    }
+
+    public function testGetPlaceWithExistingPlace(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('getPlace');
+
+        $existingPlace = $this->createMock(Place::class);
+        $freemiumEvent = new FreemiumEvent();
+        $freemiumEvent->place = $existingPlace;
+
+        $result = $eventMappingBuilder->getPlace($freemiumEvent);
+
+        $this->assertSame($existingPlace, $result);
+    }
+
+    public function testGetPlaceCreatesNewPlace(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('getPlace');
+
+        $freemiumEvent = new FreemiumEvent();
+        $freemiumEvent->place = null;
+        $freemiumEvent->placeName = 'Test Venue';
+
+        $result = $eventMappingBuilder->getPlace($freemiumEvent);
+
+        $this->assertInstanceOf(Place::class, $result);
+    }
+
+    public function testGetPlaceReturnsNullWhenNoInformation(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('getPlace');
+
+        $freemiumEvent = new FreemiumEvent();
+        $freemiumEvent->place = null;
+        $freemiumEvent->placeName = null;
+        $freemiumEvent->streetAddress = null;
+        $freemiumEvent->streetAddressSecond = null;
+        $freemiumEvent->streetAddressThird = null;
+        $freemiumEvent->postalCode = null;
+        $freemiumEvent->addressCity = null;
+
+        $result = $eventMappingBuilder->getPlace($freemiumEvent);
+
+        $this->assertNull($result);
+    }
+
+    public function testGetAddressPostalWithExistingAddress(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('getAddressPostal');
+
+        $existingAddress = $this->createMock(AddressPostal::class);
+        $place = $this->createMock(Place::class);
+        $place->method('getAddressPostal')->willReturn($existingAddress);
+
+        $result = $eventMappingBuilder->getAddressPostal($place);
+
+        $this->assertSame($existingAddress, $result);
+    }
+
+    public function testGetAddressPostalCreatesNew(): void
+    {
+        $eventMappingBuilder = $this->getEventMappingBuilderMockForMethod('getAddressPostal');
+
+        $place = $this->createMock(Place::class);
+        $place->method('getAddressPostal')->willReturn(null);
+
+        $result = $eventMappingBuilder->getAddressPostal($place);
+
+        $this->assertInstanceOf(AddressPostal::class, $result);
+    }
+}

+ 251 - 0
tests/Unit/Service/ApiResourceBuilder/Freemium/OrganizationMappingBuilderTest.php

@@ -0,0 +1,251 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Tests\Unit\Service\ApiResourceBuilder\Freemium;
+
+use App\ApiResources\Freemium\FreemiumOrganization;
+use App\Entity\Core\AddressPostal;
+use App\Entity\Core\ContactPoint;
+use App\Entity\Core\Country;
+use App\Entity\Core\File;
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\OrganizationAddressPostal;
+use App\Enum\Core\ContactPointTypeEnum;
+use App\Enum\Organization\AddressPostalOrganizationTypeEnum;
+use App\Service\ApiResourceBuilder\Freemium\OrganizationMappingBuilder;
+use Doctrine\Common\Collections\ArrayCollection;
+use libphonenumber\PhoneNumber;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class TestableOrganizationMappingBuilder extends OrganizationMappingBuilder
+{
+    public function mapOrganizationInformations(Organization $organization, FreemiumOrganization $freemiumOrganization): void
+    {
+        parent::mapOrganizationInformations($organization, $freemiumOrganization);
+    }
+
+    public function mapContactPointInformations(ContactPoint $contactPoint, FreemiumOrganization $freemiumOrganization): void
+    {
+        parent::mapContactPointInformations($contactPoint, $freemiumOrganization);
+    }
+
+    public function mapAddressPostalInformations(AddressPostal $address, FreemiumOrganization $freemiumOrganization): void
+    {
+        parent::mapAddressPostalInformations($address, $freemiumOrganization);
+    }
+
+    public function getPrincipalContactPointOrCreateNewOne(Organization $organization): ContactPoint
+    {
+        return parent::getPrincipalContactPointOrCreateNewOne($organization);
+    }
+
+    public function getPrincipalAddressPostalOrCreateNewOne(Organization $organization): AddressPostal
+    {
+        return parent::getPrincipalAddressPostalOrCreateNewOne($organization);
+    }
+}
+
+class OrganizationMappingBuilderTest extends TestCase
+{
+    private function getOrganizationMappingBuilderMockForMethod(string $methodName): TestableOrganizationMappingBuilder|MockObject
+    {
+        return $this
+            ->getMockBuilder(TestableOrganizationMappingBuilder::class)
+            ->setMethodsExcept([$methodName])
+            ->getMock();
+    }
+
+    public function testMapInformations(): void
+    {
+        $organizationMappingBuilder = $this
+            ->getMockBuilder(TestableOrganizationMappingBuilder::class)
+            ->setMethodsExcept(['mapInformations'])
+            ->getMock();
+
+        $organization = $this->createMock(Organization::class);
+        $freemiumOrganization = $this->createMock(FreemiumOrganization::class);
+        $contactPoint = $this->createMock(ContactPoint::class);
+        $addressPostal = $this->createMock(AddressPostal::class);
+
+        // Verify that methods are called in the correct order
+        $organizationMappingBuilder
+            ->expects($this->once())
+            ->method('mapOrganizationInformations')
+            ->with($organization, $freemiumOrganization);
+
+        $organizationMappingBuilder
+            ->expects($this->once())
+            ->method('getPrincipalContactPointOrCreateNewOne')
+            ->with($organization)
+            ->willReturn($contactPoint);
+
+        $organizationMappingBuilder
+            ->expects($this->once())
+            ->method('mapContactPointInformations')
+            ->with($contactPoint, $freemiumOrganization);
+
+        $organizationMappingBuilder
+            ->expects($this->once())
+            ->method('getPrincipalAddressPostalOrCreateNewOne')
+            ->with($organization)
+            ->willReturn($addressPostal);
+
+        $organizationMappingBuilder
+            ->expects($this->once())
+            ->method('mapAddressPostalInformations')
+            ->with($addressPostal, $freemiumOrganization);
+
+        $organizationMappingBuilder->mapInformations($organization, $freemiumOrganization);
+    }
+
+    public function testMapOrganizationInformations(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('mapOrganizationInformations');
+
+        $organization = $this->createMock(Organization::class);
+        $logo = $this->createMock(File::class);
+
+        $freemiumOrganization = new FreemiumOrganization();
+        $freemiumOrganization->name = 'Test Organization';
+        $freemiumOrganization->description = 'Test Description';
+        $freemiumOrganization->facebook = 'https://facebook.com/test';
+        $freemiumOrganization->youtube = 'https://youtube.com/test';
+        $freemiumOrganization->instagram = 'https://instagram.com/test';
+        $freemiumOrganization->twitter = 'https://twitter.com/test';
+        $freemiumOrganization->portailVisibility = true;
+        $freemiumOrganization->logo = $logo;
+
+        // Verify setter calls
+        $organization->expects($this->once())->method('setName')->with('Test Organization');
+        $organization->expects($this->once())->method('setDescription')->with('Test Description');
+        $organization->expects($this->once())->method('setFacebook')->with('https://facebook.com/test');
+        $organization->expects($this->once())->method('setYoutube')->with('https://youtube.com/test');
+        $organization->expects($this->once())->method('setInstagram')->with('https://instagram.com/test');
+        $organization->expects($this->once())->method('setTwitter')->with('https://twitter.com/test');
+        $organization->expects($this->once())->method('setPortailVisibility')->with(true);
+        $organization->expects($this->once())->method('setLogo')->with($logo);
+
+        $organizationMappingBuilder->mapOrganizationInformations($organization, $freemiumOrganization);
+    }
+
+    public function testMapContactPointInformations(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('mapContactPointInformations');
+
+        $contactPoint = $this->createMock(ContactPoint::class);
+        $tel = $this->createMock(PhoneNumber::class);
+
+        $freemiumOrganization = new FreemiumOrganization();
+        $freemiumOrganization->tel = $tel;
+        $freemiumOrganization->email = 'test@example.com';
+
+        $contactPoint->expects($this->once())->method('setTelphone')->with($tel);
+        $contactPoint->expects($this->once())->method('setEmail')->with('test@example.com');
+
+        $organizationMappingBuilder->mapContactPointInformations($contactPoint, $freemiumOrganization);
+    }
+
+    public function testMapAddressPostalInformations(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('mapAddressPostalInformations');
+
+        $address = $this->createMock(AddressPostal::class);
+        $country = $this->createMock(Country::class);
+
+        $freemiumOrganization = new FreemiumOrganization();
+        $freemiumOrganization->streetAddress = '123 Test Street';
+        $freemiumOrganization->streetAddressSecond = 'Apt 1';
+        $freemiumOrganization->streetAddressThird = 'Floor 2';
+        $freemiumOrganization->postalCode = '12345';
+        $freemiumOrganization->addressCity = 'Test City';
+        $freemiumOrganization->addressCountry = $country;
+        $freemiumOrganization->longitude = 2.3522;
+        $freemiumOrganization->latitude = 48.8566;
+
+        $address->expects($this->once())->method('setStreetAddress')->with('123 Test Street');
+        $address->expects($this->once())->method('setStreetAddressSecond')->with('Apt 1');
+        $address->expects($this->once())->method('setStreetAddressThird')->with('Floor 2');
+        $address->expects($this->once())->method('setPostalCode')->with('12345');
+        $address->expects($this->once())->method('setAddressCity')->with('Test City');
+        $address->expects($this->once())->method('setAddressCountry')->with($country);
+        $address->expects($this->once())->method('setLongitude')->with(2.3522);
+        $address->expects($this->once())->method('setLatitude')->with(48.8566);
+
+        $organizationMappingBuilder->mapAddressPostalInformations($address, $freemiumOrganization);
+    }
+
+    public function testGetPrincipalContactPointOrCreateNewOneWithExisting(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('getPrincipalContactPointOrCreateNewOne');
+
+        $organization = $this->createMock(Organization::class);
+        $existingContactPoint = $this->createMock(ContactPoint::class);
+
+        $organization->expects($this->once())
+            ->method('getPrincipalContactPoint')
+            ->willReturn($existingContactPoint);
+
+        $result = $organizationMappingBuilder->getPrincipalContactPointOrCreateNewOne($organization);
+
+        $this->assertSame($existingContactPoint, $result);
+    }
+
+    public function testGetPrincipalContactPointOrCreateNewOneCreatesNew(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('getPrincipalContactPointOrCreateNewOne');
+
+        $organization = $this->createMock(Organization::class);
+
+        $organization->expects($this->once())
+            ->method('getPrincipalContactPoint')
+            ->willReturn(null);
+
+        $organization->expects($this->once())
+            ->method('addContactPoint')
+            ->with($this->isInstanceOf(ContactPoint::class));
+
+        $result = $organizationMappingBuilder->getPrincipalContactPointOrCreateNewOne($organization);
+
+        $this->assertSame(ContactPointTypeEnum::PRINCIPAL, $result->getContactType());
+    }
+
+    public function testGetPrincipalAddressPostalOrCreateNewOneWithExisting(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('getPrincipalAddressPostalOrCreateNewOne');
+
+        $organization = $this->createMock(Organization::class);
+        $existingAddressPostal = $this->createMock(AddressPostal::class);
+        $existingOrganizationAddressPostal = $this->createMock(OrganizationAddressPostal::class);
+
+        $existingOrganizationAddressPostal->expects($this->once())
+            ->method('getAddressPostal')
+            ->willReturn($existingAddressPostal);
+
+        $organization->expects($this->once())
+            ->method('getPrincipalAddressPostal')
+            ->willReturn($existingOrganizationAddressPostal);
+
+        $result = $organizationMappingBuilder->getPrincipalAddressPostalOrCreateNewOne($organization);
+
+        $this->assertSame($existingAddressPostal, $result);
+    }
+
+    public function testGetPrincipalAddressPostalOrCreateNewOneCreatesNew(): void
+    {
+        $organizationMappingBuilder = $this->getOrganizationMappingBuilderMockForMethod('getPrincipalAddressPostalOrCreateNewOne');
+
+        $organization = $this->createMock(Organization::class);
+
+        $organization->expects($this->once())
+            ->method('getPrincipalAddressPostal')
+            ->willReturn(null);
+
+        $organization->expects($this->once())
+            ->method('addOrganizationAddressPostal')
+            ->with($this->isInstanceOf(OrganizationAddressPostal::class));
+
+        $result = $organizationMappingBuilder->getPrincipalAddressPostalOrCreateNewOne($organization);
+    }
+}

+ 367 - 0
tests/Unit/Service/State/Provider/ProviderUtilsTest.php

@@ -0,0 +1,367 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Tests\Unit\Service\State\Provider;
+
+use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
+use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
+use ApiPlatform\Metadata\Operation;
+use ApiPlatform\State\Pagination\Pagination;
+use ApiPlatform\State\Pagination\TraversablePaginator;
+use App\Service\State\Provider\ProviderUtils;
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\ORM\EntityManagerInterface;
+use Doctrine\ORM\EntityRepository;
+use Doctrine\ORM\Query;
+use Doctrine\ORM\QueryBuilder;
+use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class ProviderUtilsTest extends TestCase
+{
+    private ProviderUtils $providerUtils;
+    private EntityManagerInterface|MockObject $entityManager;
+    private Pagination $pagination;
+    private QueryCollectionExtensionInterface|MockObject $extension1;
+    private QueryCollectionExtensionInterface|MockObject $extension2;
+
+    protected function setUp(): void
+    {
+        $this->entityManager = $this->createMock(EntityManagerInterface::class);
+        $this->pagination = new Pagination(['enabled' => true]);
+        $this->extension1 = $this->createMock(QueryCollectionExtensionInterface::class);
+        $this->extension2 = $this->createMock(QueryCollectionExtensionInterface::class);
+    }
+
+    private function getProviderUtilsMockForMethod(string $methodName): ProviderUtils|MockObject
+    {
+        $providerUtils = $this
+            ->getMockBuilder(ProviderUtils::class)
+            ->setConstructorArgs([
+                $this->entityManager,
+                [$this->extension1, $this->extension2],
+                $this->pagination
+            ])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
+
+        return $providerUtils;
+    }
+
+    public function testApplyCollectionExtensionsAndPagination(): void
+    {
+        $providerUtils = $this->getProviderUtilsMockForMethod('applyCollectionExtensionsAndPagination');
+
+        $entityClass = 'App\Entity\Test\TestEntity';
+        $operation = $this->createMock(Operation::class);
+        $context = ['filters' => ['name' => 'test']];
+
+        $platform = $this->createMock(AbstractPlatform::class);
+        $connection = $this->createMock(Connection::class);
+        $connection->expects(self::any())->method('getDatabasePlatform')->willReturn($platform);
+
+        $query = $this->createMock(Query::class);
+        $query->method('getEntityManager')->willReturn($this->entityManager);
+
+        $queryBuilder = $this->createMock(QueryBuilder::class);
+        $queryBuilder->method('getQuery')->willReturn($query);
+        $queryBuilder->method('getEntityManager')->willReturn($this->entityManager);
+
+        $repository = $this->createMock(EntityRepository::class);
+
+        $repository
+            ->expects(self::once())
+            ->method('createQueryBuilder')
+            ->with('o')
+            ->willReturn($queryBuilder);
+
+        $this->entityManager
+            ->expects(self::once())
+            ->method('getRepository')
+            ->with($entityClass)
+            ->willReturn($repository);
+
+        $this->entityManager
+            ->method('getConnection')
+            ->willReturn($connection);
+
+        // Mock extensions applying to the query
+        $this->extension1
+            ->expects(self::once())
+            ->method('applyToCollection')
+            ->with(
+                $queryBuilder,
+                self::isInstanceOf(QueryNameGenerator::class),
+                $entityClass,
+                $operation,
+                $context
+            );
+
+        $this->extension2
+            ->expects(self::once())
+            ->method('applyToCollection')
+            ->with(
+                $queryBuilder,
+                self::isInstanceOf(QueryNameGenerator::class),
+                $entityClass,
+                $operation,
+                $context
+            );
+
+        // Real pagination will be used
+
+        $result = $providerUtils->applyCollectionExtensionsAndPagination($entityClass, $operation, $context);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+    }
+
+    public function testApplyCollectionExtensionsAndPaginationWithoutContext(): void
+    {
+        $providerUtils = $this->getProviderUtilsMockForMethod('applyCollectionExtensionsAndPagination');
+
+        $entityClass = 'App\Entity\Test\TestEntity';
+        $operation = $this->createMock(Operation::class);
+
+        $platform = $this->createMock(AbstractPlatform::class);
+        $connection = $this->createMock(Connection::class);
+        $connection->expects(self::any())->method('getDatabasePlatform')->willReturn($platform);
+
+        $query = $this->createMock(Query::class);
+        $query->method('getEntityManager')->willReturn($this->entityManager);
+
+        $queryBuilder = $this->createMock(QueryBuilder::class);
+        $queryBuilder->method('getQuery')->willReturn($query);
+        $queryBuilder->method('getEntityManager')->willReturn($this->entityManager);
+
+        $repository = $this->createMock(EntityRepository::class);
+
+        $repository
+            ->expects(self::once())
+            ->method('createQueryBuilder')
+            ->with('o')
+            ->willReturn($queryBuilder);
+
+        $this->entityManager
+            ->expects(self::once())
+            ->method('getRepository')
+            ->with($entityClass)
+            ->willReturn($repository);
+
+        $this->entityManager
+            ->method('getConnection')
+            ->willReturn($connection);
+
+        // Extensions should still be applied with empty context
+        $this->extension1
+            ->expects(self::once())
+            ->method('applyToCollection')
+            ->with(
+                $queryBuilder,
+                self::isInstanceOf(QueryNameGenerator::class),
+                $entityClass,
+                $operation,
+                []
+            );
+
+        $this->extension2
+            ->expects(self::once())
+            ->method('applyToCollection')
+            ->with(
+                $queryBuilder,
+                self::isInstanceOf(QueryNameGenerator::class),
+                $entityClass,
+                $operation,
+                []
+            );
+
+        $result = $providerUtils->applyCollectionExtensionsAndPagination($entityClass, $operation);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+    }
+
+    public function testApplyCollectionExtensionsAndPaginationWithNonQueryCollectionExtension(): void
+    {
+        $entityClass = 'App\Entity\Test\TestEntity';
+        $operation = $this->createMock(Operation::class);
+
+        $nonQueryExtension = new class {};
+
+        $providerUtils = $this
+            ->getMockBuilder(ProviderUtils::class)
+            ->setConstructorArgs([
+                $this->entityManager,
+                [$this->extension1, $nonQueryExtension, $this->extension2],
+                $this->pagination
+            ])
+            ->setMethodsExcept(['applyCollectionExtensionsAndPagination'])
+            ->getMock();
+
+        $platform = $this->createMock(AbstractPlatform::class);
+        $connection = $this->createMock(Connection::class);
+        $connection->expects(self::any())->method('getDatabasePlatform')->willReturn($platform);
+
+        $query = $this->createMock(Query::class);
+        $query->method('getEntityManager')->willReturn($this->entityManager);
+
+        $queryBuilder = $this->createMock(QueryBuilder::class);
+        $queryBuilder->method('getQuery')->willReturn($query);
+        $queryBuilder->method('getEntityManager')->willReturn($this->entityManager);
+
+        $repository = $this->createMock(EntityRepository::class);
+
+        $repository
+            ->expects(self::once())
+            ->method('createQueryBuilder')
+            ->with('o')
+            ->willReturn($queryBuilder);
+
+        $this->entityManager
+            ->expects(self::once())
+            ->method('getRepository')
+            ->with($entityClass)
+            ->willReturn($repository);
+
+        $this->entityManager
+            ->method('getConnection')
+            ->willReturn($connection);
+
+        $this->extension1
+            ->expects(self::once())
+            ->method('applyToCollection');
+
+        $this->extension2
+            ->expects(self::once())
+            ->method('applyToCollection');
+
+        $result = $providerUtils->applyCollectionExtensionsAndPagination($entityClass, $operation);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+    }
+
+    public function testApplyCollectionExtensionsAndPaginationCreatesCorrectDoctrinePaginator(): void
+    {
+        $providerUtils = $this->getProviderUtilsMockForMethod('applyCollectionExtensionsAndPagination');
+
+        $entityClass = 'App\Entity\Test\TestEntity';
+        $operation = $this->createMock(Operation::class);
+
+        $platform = $this->createMock(AbstractPlatform::class);
+        $connection = $this->createMock(Connection::class);
+        $connection->expects(self::any())->method('getDatabasePlatform')->willReturn($platform);
+
+        $query = $this->createMock(Query::class);
+        $query->method('getEntityManager')->willReturn($this->entityManager);
+
+        $queryBuilder = $this->createMock(QueryBuilder::class);
+        $queryBuilder->method('getQuery')->willReturn($query);
+        $queryBuilder->method('getEntityManager')->willReturn($this->entityManager);
+
+        $repository = $this->createMock(EntityRepository::class);
+
+        $repository
+            ->expects(self::once())
+            ->method('createQueryBuilder')
+            ->with('o')
+            ->willReturn($queryBuilder);
+
+        $this->entityManager
+            ->expects(self::once())
+            ->method('getRepository')
+            ->with($entityClass)
+            ->willReturn($repository);
+
+        $this->entityManager
+            ->method('getConnection')
+            ->willReturn($connection);
+
+        $this->extension1
+            ->expects(self::once())
+            ->method('applyToCollection');
+
+        $this->extension2
+            ->expects(self::once())
+            ->method('applyToCollection');
+
+        // Real pagination will be used
+
+        $result = $providerUtils->applyCollectionExtensionsAndPagination($entityClass, $operation);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+    }
+
+    public function testGetTraversablePaginator(): void
+    {
+        $providerUtils = $this->getProviderUtilsMockForMethod('getTraversablePaginator');
+
+        $mappedItems = ['item1', 'item2', 'item3'];
+        $originalPaginator = new TraversablePaginator(
+            new \ArrayIterator(['original1', 'original2']),
+            2,
+            10,
+            50
+        );
+
+        $result = $providerUtils->getTraversablePaginator($mappedItems, $originalPaginator);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+        $this->assertEquals(2, $result->getCurrentPage());
+        $this->assertEquals(10, $result->getItemsPerPage());
+        $this->assertEquals(50, $result->getTotalItems());
+
+        // Test that the iterator contains the mapped items
+        $resultItems = iterator_to_array($result->getIterator());
+        $this->assertSame($mappedItems, $resultItems);
+    }
+
+    public function testGetTraversablePaginatorWithEmptyMappedItems(): void
+    {
+        $providerUtils = $this->getProviderUtilsMockForMethod('getTraversablePaginator');
+
+        $mappedItems = [];
+        $originalPaginator = new TraversablePaginator(
+            new \ArrayIterator([]),
+            1,
+            30,
+            0
+        );
+
+        $result = $providerUtils->getTraversablePaginator($mappedItems, $originalPaginator);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+        $this->assertEquals(1, $result->getCurrentPage());
+        $this->assertEquals(30, $result->getItemsPerPage());
+        $this->assertEquals(0, $result->getTotalItems());
+        $this->assertEmpty(iterator_to_array($result->getIterator()));
+    }
+
+    public function testGetTraversablePaginatorWithComplexMappedItems(): void
+    {
+        $providerUtils = $this->getProviderUtilsMockForMethod('getTraversablePaginator');
+
+        $mappedItems = [
+            ['id' => 1, 'name' => 'Item 1'],
+            ['id' => 2, 'name' => 'Item 2'],
+            (object)['id' => 3, 'name' => 'Item 3'],
+        ];
+        $originalPaginator = new TraversablePaginator(
+            new \ArrayIterator(['original1', 'original2', 'original3']),
+            3,
+            5,
+            100
+        );
+
+        $result = $providerUtils->getTraversablePaginator($mappedItems, $originalPaginator);
+
+        $this->assertInstanceOf(TraversablePaginator::class, $result);
+        $this->assertEquals(3, $result->getCurrentPage());
+        $this->assertEquals(5, $result->getItemsPerPage());
+        $this->assertEquals(100, $result->getTotalItems());
+
+        $resultItems = iterator_to_array($result->getIterator());
+        $this->assertCount(3, $resultItems);
+        $this->assertSame($mappedItems, $resultItems);
+    }
+}

+ 57 - 0
tests/Unit/Service/Twig/ToBase64ExtensionTest.php

@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Tests\Unit\Service\Twig;
+
+use App\Service\Twig\ToBase64Extension;
+use Path\Path;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Twig\TwigFilter;
+
+class ToBase64ExtensionTest extends TestCase
+{
+    private string $projectDir = '/test/project';
+
+    private function getToBase64ExtensionMockFor(string $methodName): ToBase64Extension|MockObject
+    {
+        return $this->getMockBuilder(ToBase64Extension::class)
+            ->setConstructorArgs([$this->projectDir])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
+    }
+
+    /**
+     * @see ToBase64Extension::getFilters()
+     */
+    public function testGetFilters(): void
+    {
+        $extension = $this->getToBase64ExtensionMockFor('getFilters');
+        $filters = $extension->getFilters();
+
+        $this->assertIsArray($filters);
+        $this->assertCount(1, $filters);
+        $this->assertInstanceOf(TwigFilter::class, $filters[0]);
+        $this->assertSame('img_to_base64', $filters[0]->getName());
+
+        // Test that the callable is correctly set
+        $callable = $filters[0]->getCallable();
+        $this->assertIsArray($callable);
+        $this->assertSame($extension, $callable[0]);
+        $this->assertSame('imgToBase64', $callable[1]);
+    }
+
+    /**
+     * @see ToBase64Extension::imgToBase64()
+     */
+    public function testImgToBase64WithNonExistentFile(): void
+    {
+        $extension = $this->getToBase64ExtensionMockFor('imgToBase64');
+
+        // Test with a non-existent file - this should return empty string without file operations
+        $result = $extension->imgToBase64('non-existent-image.jpg');
+
+        $this->assertSame('', $result);
+    }
+}

+ 27 - 52
tests/Unit/Service/Typo3/Typo3ServiceTest.php

@@ -1,11 +1,11 @@
 <?php
 
-/** @noinspection PhpUnhandledExceptionInspection */
-
 namespace App\Tests\Unit\Service\Typo3;
 
 use App\Service\Typo3\Typo3Service;
 use App\Service\Utils\DatesUtils;
+use PHPUnit\Framework\MockObject\MockBuilder;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 use Symfony\Contracts\HttpClient\ResponseInterface;
@@ -20,11 +20,22 @@ class TestableTypo3Service extends Typo3Service
 
 class Typo3ServiceTest extends TestCase
 {
-    private HttpClientInterface $typo3Client;
+    private HttpClientInterface|MockObject $typo3Client;
 
     public function setUp(): void
     {
-        $this->typo3Client = $this->getMockBuilder(HttpClientInterface::class)->disableOriginalConstructor()->getMock();
+        $this->typo3Client = $this
+            ->getMockBuilder(HttpClientInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getTypo3ServiceMockFor(string $methodName): TestableTypo3Service|MockObject
+    {
+        return $this->getMockBuilder(TestableTypo3Service::class)
+            ->setConstructorArgs([$this->typo3Client])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
     }
 
     /**
@@ -40,10 +51,7 @@ class Typo3ServiceTest extends TestCase
             ->with('GET', '/typo3/foo?param=bar')
             ->willReturn($response);
 
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setConstructorArgs([$this->typo3Client])
-            ->setMethodsExcept(['sendCommand'])
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('sendCommand');
 
         $typo3Service->sendCommand('foo', ['param' => 'bar']);
     }
@@ -53,10 +61,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testClearSiteCache(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['clearSiteCache'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('clearSiteCache');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -72,10 +77,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testCreateSite(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['createSite'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('createSite');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -91,10 +93,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testUpdateSite(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['updateSite'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('updateSite');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -110,10 +109,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testDeleteSite(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['deleteSite'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('deleteSite');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -131,10 +127,7 @@ class Typo3ServiceTest extends TestCase
     {
         DatesUtils::setFakeDatetime('2025-01-01 00:00:00');
 
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['hardDeleteSite'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('hardDeleteSite');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
 
@@ -155,10 +148,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testUndeleteSite(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['undeleteSite'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('undeleteSite');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -174,10 +164,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testSetSiteDomain(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['setSiteDomain'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('setSiteDomain');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -193,10 +180,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testSetSiteDomainWithRedirection(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['setSiteDomain'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('setSiteDomain');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -212,10 +196,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testResetSitePerms(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['resetSitePerms'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('resetSitePerms');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -231,10 +212,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testGetSiteStatus(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['getSiteStatus'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('getSiteStatus');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
@@ -250,10 +228,7 @@ class Typo3ServiceTest extends TestCase
      */
     public function testAddRedirection(): void
     {
-        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
-            ->setMethodsExcept(['addRedirection'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $typo3Service = $this->getTypo3ServiceMockFor('addRedirection');
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())