container = new DefaultContainer(); // Prä-Registriere stdClass als echte Klasse um Lazy Loading zu vermeiden $this->container->bind(stdClass::class, fn () => new stdClass()); } /** * Test ob der Container unbegrenzt wächst bei wiederholten Aufrufen */ public function test_container_does_not_grow_indefinitely(): void { $initialMemory = memory_get_usage(true); // Simuliere viele Requests mit direkten Instanzen (vermeidet Lazy Loading) for ($i = 0; $i < 1000; $i++) { $serviceName = "service_$i"; // Erstelle Objekt direkt und registriere als Instanz $obj = new stdClass(); $obj->id = $i; $obj->data = str_repeat('x', 100); $this->container->instance($serviceName, $obj); $instance = $this->container->get($serviceName); $this->assertEquals($i, $instance->id); } $finalMemory = memory_get_usage(true); $memoryGrowth = $finalMemory - $initialMemory; // Memory growth sollte unter 5MB bleiben für 1000 Services $this->assertLessThan( 5 * 1024 * 1024, $memoryGrowth, "Container memory grew by " . number_format($memoryGrowth) . " bytes for 1000 services" ); echo "\nMemory growth for 1000 services: " . number_format($memoryGrowth) . " bytes\n"; } /** * Test ob die InstanceRegistry ordnungsgemäß aufräumt */ public function test_instance_registry_can_be_flushed(): void { $registry = new InstanceRegistry(); // Fülle Registry mit vielen Instanzen for ($i = 0; $i < 100; $i++) { $serviceName = "TestInstance_$i"; $instance = (object)['id' => $i, 'data' => "test_$i"]; $registry->setInstance($serviceName, $instance); } // Prüfe dass Instanzen registriert sind $this->assertCount(100, $registry->getAllRegistered()); // Flush sollte alles löschen $registry->flush(); $this->assertCount(0, $registry->getAllRegistered()); } /** * Test ob Singletons ordnungsgemäß verwaltet werden * Test nutzt InstanceRegistry direkt da singleton() auch lazy loading versucht */ public function test_singleton_lifecycle(): void { $serviceName = 'singleton_service'; // Erstelle Objekt direkt und registriere als Singleton über InstanceRegistry $obj = new stdClass(); $obj->data = 'test'; $obj->created_at = time(); // Direktes Setzen als Singleton über die Registry $registry = new InstanceRegistry(); $registry->setSingleton($serviceName, $obj); // Container mit dieser Registry erstellen $container = new DefaultContainer(instances: $registry); // Sollte immer die gleiche Instanz zurückgeben $instance1 = $container->get($serviceName); $instance2 = $container->get($serviceName); $this->assertSame($instance1, $instance2); $this->assertEquals('test', $instance1->data); } /** * Test ob Container-Cache bei bind() ordnungsgemäß geleert wird */ public function test_container_cache_clearing(): void { $serviceName = 'cache_service'; // Erste Instanz $obj1 = new stdClass(); $obj1->version = 1; $this->container->instance($serviceName, $obj1); $instance1 = $this->container->get($serviceName); // Neue Instanz sollte alte überschreiben $obj2 = new stdClass(); $obj2->version = 2; $this->container->instance($serviceName, $obj2); $instance2 = $this->container->get($serviceName); $this->assertNotSame($instance1, $instance2); $this->assertEquals(1, $instance1->version); $this->assertEquals(2, $instance2->version); } /** * Test Memory Usage unter Last */ public function test_memory_usage_under_load(): void { $memoryBefore = memory_get_usage(true); $maxMemoryUsed = 0; // Simuliere Last von 500 verschiedenen Services for ($iteration = 0; $iteration < 5; $iteration++) { for ($i = 0; $i < 100; $i++) { $serviceName = "load_service_{$iteration}_{$i}"; // Erstelle Service-Objekt direkt $obj = new stdClass(); $obj->data = array_fill(0, 100, 'load_test_data'); $obj->timestamp = microtime(true); $obj->random = random_bytes(256); $this->container->instance($serviceName, $obj); $instance = $this->container->get($serviceName); $this->assertCount(100, $instance->data); $currentMemory = memory_get_usage(true); $maxMemoryUsed = max($maxMemoryUsed, $currentMemory - $memoryBefore); } // Optional: Garbage collection nach jeder Iteration gc_collect_cycles(); } $finalMemory = memory_get_usage(true); $totalGrowth = $finalMemory - $memoryBefore; // Container sollte nicht unbegrenzt wachsen $this->assertLessThan( 20 * 1024 * 1024, $totalGrowth, "Container grew by " . number_format($totalGrowth) . " bytes under load" ); echo "\nMemory Statistics:\n"; echo "- Initial Memory: " . number_format($memoryBefore) . " bytes\n"; echo "- Final Memory: " . number_format($finalMemory) . " bytes\n"; echo "- Total Growth: " . number_format($totalGrowth) . " bytes\n"; echo "- Max Memory Used: " . number_format($maxMemoryUsed) . " bytes\n"; } /** * Test Performance von Container-Lookups */ public function test_container_lookup_performance(): void { // Setup: 1000 Services als Instanzen registrieren for ($i = 0; $i < 1000; $i++) { $serviceName = "perf_service_$i"; $obj = new stdClass(); $obj->id = $i; $obj->name = "service_$i"; $this->container->instance($serviceName, $obj); } $startTime = microtime(true); // Performance Test: 10000 Lookups for ($i = 0; $i < 10000; $i++) { $serviceName = "perf_service_" . ($i % 1000); $instance = $this->container->get($serviceName); $this->assertEquals($i % 1000, $instance->id); } $endTime = microtime(true); $duration = $endTime - $startTime; // Sollte unter 1 Sekunde bleiben für 10k Lookups $this->assertLessThan( 1.0, $duration, "Container lookups took {$duration}s for 10k operations" ); echo "\nPerformance: " . number_format(10000 / $duration, 0) . " lookups/second\n"; } }