Files
Gnuboard7/tests/Unit/Extension/AbstractExtensionServiceProviderTest.php
T
2026-07-01 10:30:32 +09:00

162 lines
6.1 KiB
PHP

<?php
namespace Tests\Unit\Extension;
use App\Contracts\Extension\CacheableExtensionInterface;
use App\Contracts\Extension\CacheInterface;
use App\Contracts\Extension\StorageInterface;
use App\Extension\AbstractExtensionServiceProvider;
use Mockery;
use Tests\TestCase;
require_once __DIR__.'/ServiceProviderTestFixtures.php';
/**
* AbstractExtensionServiceProvider 공통 자동 바인딩 동작 검증.
*
* - $repositories 배열은 interface → implementation 으로 바인딩된다.
* - $cacheServices 배열은 contextual binding 으로 확장 캐시를 주입한다.
* - $storageServices 배열은 contextual binding 으로 확장 스토리지를 주입한다.
* - 글로벌 CacheInterface / StorageInterface 바인딩은 덮어쓰지 않는다.
*/
class AbstractExtensionServiceProviderTest extends TestCase
{
public function test_repositories_bind_interface_to_implementation(): void
{
$extension = Mockery::mock(CacheableExtensionInterface::class);
$provider = new TestExtensionServiceProviderFixture($this->app, $extension);
$provider->setRepositories([
FixtureRepositoryInterface::class => FixtureRepositoryImpl::class,
]);
$provider->register();
$resolved = $this->app->make(FixtureRepositoryInterface::class);
$this->assertInstanceOf(FixtureRepositoryImpl::class, $resolved);
}
/**
* @scenario extension_kind=plugin,service_kind=cache_service,global_binding_state=absent,manager_state=plugin_resolved,consumer_type=single_class
* @effects cache_service_receives_plugin_cache_driver_with_correct_identifier_prefix, inicis_identity_provider_receives_correctly_prefixed_plugin_cache
*/
public function test_cache_services_receive_extension_cache_via_contextual_binding(): void
{
$cache = Mockery::mock(CacheInterface::class);
$extension = Mockery::mock(CacheableExtensionInterface::class);
$extension->shouldReceive('getCache')->andReturn($cache);
$provider = new TestExtensionServiceProviderFixture($this->app, $extension);
$provider->setCacheServices([FixtureCacheConsumer::class]);
$provider->register();
$consumer = $this->app->make(FixtureCacheConsumer::class);
$this->assertSame($cache, $consumer->cache);
}
/**
* @scenario extension_kind=plugin,service_kind=storage_service,global_binding_state=absent,manager_state=plugin_resolved,consumer_type=single_class
* @effects storage_service_receives_plugin_storage_driver_with_correct_disk
*/
public function test_storage_services_receive_extension_storage_via_contextual_binding(): void
{
$storage = Mockery::mock(StorageInterface::class);
$extension = Mockery::mock(CacheableExtensionInterface::class);
$extension->shouldReceive('getStorage')->andReturn($storage);
$provider = new TestExtensionServiceProviderFixture($this->app, $extension);
$provider->setStorageServices([FixtureStorageConsumer::class]);
$provider->register();
$consumer = $this->app->make(FixtureStorageConsumer::class);
$this->assertSame($storage, $consumer->storage);
}
public function test_register_does_not_rebind_global_cache_or_storage_interface(): void
{
$globalCache = Mockery::mock(CacheInterface::class);
$this->app->instance(CacheInterface::class, $globalCache);
$globalStorage = Mockery::mock(StorageInterface::class);
$this->app->instance(StorageInterface::class, $globalStorage);
$extension = Mockery::mock(CacheableExtensionInterface::class);
$extension->shouldReceive('getCache')->andReturn(Mockery::mock(CacheInterface::class));
$extension->shouldReceive('getStorage')->andReturn(Mockery::mock(StorageInterface::class));
$provider = new TestExtensionServiceProviderFixture($this->app, $extension);
$provider->setCacheServices([FixtureCacheConsumer::class]);
$provider->setStorageServices([FixtureStorageConsumer::class]);
$provider->register();
$this->assertSame($globalCache, $this->app->make(CacheInterface::class));
$this->assertSame($globalStorage, $this->app->make(StorageInterface::class));
}
/**
* @scenario extension_kind=plugin,service_kind=cache_service,global_binding_state=absent,manager_state=plugin_resolved,consumer_type=no_registration
* @effects empty_service_arrays_skip_contextual_binding_entirely
*/
public function test_empty_arrays_skip_contextual_bindings(): void
{
$extension = Mockery::mock(CacheableExtensionInterface::class);
$extension->shouldNotReceive('getCache');
$extension->shouldNotReceive('getStorage');
$provider = new TestExtensionServiceProviderFixture($this->app, $extension);
$provider->register();
$this->assertTrue(true);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
}
/**
* 테스트 fixture: 확장 인스턴스를 직접 주입받는 ServiceProvider.
*/
class TestExtensionServiceProviderFixture extends AbstractExtensionServiceProvider
{
protected string $extensionIdentifier = 'fixture-extension';
private CacheableExtensionInterface $extension;
public function __construct($app, CacheableExtensionInterface $extension)
{
parent::__construct($app);
$this->extension = $extension;
}
protected function resolveExtension(): CacheableExtensionInterface
{
return $this->extension;
}
public function setRepositories(array $repositories): void
{
$this->repositories = $repositories;
}
public function setCacheServices(array $services): void
{
$this->cacheServices = $services;
}
public function setStorageServices(array $services): void
{
$this->storageServices = $services;
}
}
// 공유 fixture (FixtureRepositoryInterface / FixtureRepositoryImpl /
// FixtureCacheConsumer / FixtureStorageConsumer) 는 ServiceProviderTestFixtures.php
// 에 정의되어 있으며 PSR-4 / composer classmap 으로 자동 로드됩니다.