From 181c9c74a73fea203c0e77dcdb9e7e4dbd2ad7d7 Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Mon, 30 Apr 2012 21:43:40 -0500 Subject: [PATCH 1/3] Improved unit tests for Zend\ServiceManager [zen-33] --- src/AbstractFactoryInterface.php | 3 +- src/Di/DiAbstractServiceFactory.php | 31 ++- src/Di/DiInstanceManagerProxy.php | 33 ++- src/Di/DiServiceFactory.php | 66 +++-- src/Di/DiServiceInitializer.php | 10 +- ...ion.php => ServiceNotCreatedException.php} | 2 +- src/FactoryInterface.php | 2 +- src/ServiceManager.php | 186 +++++++++----- src/Validator.php | 0 test/ServiceManagerTest.php | 232 ++++++++++++++---- test/TestAsset/Foo.php | 8 + test/TestAsset/FooAbstractFactory.php | 17 ++ test/TestAsset/FooFactory.php | 14 ++ test/TestAsset/FooInitializer.php | 26 ++ 14 files changed, 477 insertions(+), 153 deletions(-) rename src/Exception/{InstanceNotCreatedException.php => ServiceNotCreatedException.php} (52%) delete mode 100644 src/Validator.php create mode 100644 test/TestAsset/Foo.php create mode 100644 test/TestAsset/FooAbstractFactory.php create mode 100644 test/TestAsset/FooFactory.php create mode 100644 test/TestAsset/FooInitializer.php diff --git a/src/AbstractFactoryInterface.php b/src/AbstractFactoryInterface.php index 24d47da7..33acd25b 100644 --- a/src/AbstractFactoryInterface.php +++ b/src/AbstractFactoryInterface.php @@ -4,5 +4,6 @@ interface AbstractFactoryInterface { - public function createServiceWithName(ServiceManager $serviceManager, $name); + public function canCreateServiceWithName($name /*, $requestedName */); + public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name /*, $requestedName */); } \ No newline at end of file diff --git a/src/Di/DiAbstractServiceFactory.php b/src/Di/DiAbstractServiceFactory.php index 2bb102b9..55524c23 100644 --- a/src/Di/DiAbstractServiceFactory.php +++ b/src/Di/DiAbstractServiceFactory.php @@ -3,17 +3,21 @@ namespace Zend\ServiceManager\Di; use Zend\ServiceManager\AbstractFactoryInterface, - Zend\ServiceManager\ServiceManager, + Zend\ServiceManager\ServiceLocatorInterface, Zend\Di\Di; class DiAbstractServiceFactory extends DiServiceFactory implements AbstractFactoryInterface { - public function __construct(Di $di, $useServiceManager = self::USE_SM_NONE) + /** + * @param \Zend\Di\Di $di + * @param null|string|\Zend\Di\InstanceManager $useServiceLocator + */ + public function __construct(Di $di, $useServiceLocator = self::USE_SL_NONE) { $this->di = $di; - if (in_array($useServiceManager, array(self::USE_SM_BEFORE_DI, self::USE_SM_AFTER_DI, self::USE_SM_NONE))) { - $this->useServiceManager = $useServiceManager; + if (in_array($useServiceLocator, array(self::USE_SL_BEFORE_DI, self::USE_SL_AFTER_DI, self::USE_SL_NONE))) { + $this->useServiceManager = $useServiceLocator; } // since we are using this in a proxy-fashion, localize state @@ -21,10 +25,15 @@ public function __construct(Di $di, $useServiceManager = self::USE_SM_NONE) $this->instanceManager = $this->di->instanceManager; } - - public function createServiceWithName(ServiceManager $serviceManager, $serviceName, $requestedName = null) + /** + * @param ServiceLocatorInterface $serviceLocator + * @param $serviceName + * @param null $requestedName + * @return object + */ + public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $serviceName, $requestedName = null) { - $this->serviceManager = $serviceManager; + $this->serviceLocator = $serviceLocator; if ($requestedName) { return $this->get($requestedName, array(), true); } else { @@ -33,4 +42,12 @@ public function createServiceWithName(ServiceManager $serviceManager, $serviceNa } + /** + * @param $name + * @return null + */ + public function canCreateServiceWithName($name) + { + return null; // not sure + } } diff --git a/src/Di/DiInstanceManagerProxy.php b/src/Di/DiInstanceManagerProxy.php index 6bab0cab..8c3747ba 100644 --- a/src/Di/DiInstanceManagerProxy.php +++ b/src/Di/DiInstanceManagerProxy.php @@ -3,28 +3,47 @@ namespace Zend\ServiceManager\Di; use Zend\Di\InstanceManager as DiInstanceManager, - Zend\ServiceManager\ServiceManager; + Zend\ServiceManager\ServiceLocatorInterface; class DiInstanceManagerProxy extends DiInstanceManager { + /** + * @var DiInstanceManager + */ protected $diInstanceManager = null; - protected $serviceManager = null; - public function __construct(DiInstanceManager $diInstanceManager, ServiceManager $serviceManager) + /** + * @var ServiceLocatorInterface + */ + protected $serviceLocator = null; + + /** + * @param DiInstanceManager $diInstanceManager + * @param ServiceLocatorInterface $serviceLocator + */ + public function __construct(DiInstanceManager $diInstanceManager, ServiceLocatorInterface $serviceLocator) { $this->diInstanceManager = $diInstanceManager; - $this->serviceManager = $serviceManager; + $this->serviceLocator = $serviceLocator; } + /** + * @param $classOrAlias + * @return bool + */ public function hasSharedInstance($classOrAlias) { - return ($this->serviceManager->has($classOrAlias) || $this->diInstanceManager->hasSharedInstance($classOrAlias)); + return ($this->serviceLocator->has($classOrAlias) || $this->diInstanceManager->hasSharedInstance($classOrAlias)); } + /** + * @param $classOrAlias + * @return mixed + */ public function getSharedInstance($classOrAlias) { - if ($this->serviceManager->has($classOrAlias)) { - return $this->serviceManager->get($classOrAlias); + if ($this->serviceLocator->has($classOrAlias)) { + return $this->serviceLocator->get($classOrAlias); } else { return $this->diInstanceManager->getSharedInstance($classOrAlias); } diff --git a/src/Di/DiServiceFactory.php b/src/Di/DiServiceFactory.php index be81ceaf..673090d5 100644 --- a/src/Di/DiServiceFactory.php +++ b/src/Di/DiServiceFactory.php @@ -4,35 +4,59 @@ use Zend\ServiceManager\FactoryInterface, - Zend\ServiceManager\ServiceManager, + Zend\ServiceManager\ServiceLocatorInterface, Zend\ServiceManager\Exception, Zend\Di\Di, Zend\Di\Exception\ClassNotFoundException as DiClassNotFoundException; class DiServiceFactory extends Di implements FactoryInterface { - const USE_SM_BEFORE_DI = 'before'; - const USE_SM_AFTER_DI = 'after'; - const USE_SM_NONE = 'none'; + /**@#+ + * constants + */ + const USE_SL_BEFORE_DI = 'before'; + const USE_SL_AFTER_DI = 'after'; + const USE_SL_NONE = 'none'; + /**@#-*/ + /** + * @var \Zend\Di\Di + */ protected $di = null; + + /** + * @var \Zend\Di\InstanceManager + */ protected $name = null; + + /** + * @var array + */ protected $parameters = array(); - protected $useServiceManager = self::USE_SM_AFTER_DI; /** - * @var ServiceManager + * @var string */ - protected $serviceManager = null; + protected $useServiceLocator = self::USE_SL_AFTER_DI; + /** + * @var ServiceLocatorInterface + */ + protected $serviceLocator = null; - public function __construct(Di $di, $name, array $parameters = array(), $useServiceManager = self::USE_SM_NONE) + /** + * @param \Zend\Di\Di $di + * @param null|\Zend\Di\InstanceManager $name + * @param array $parameters + * @param string $useServiceLocator + */ + public function __construct(Di $di, $name, array $parameters = array(), $useServiceLocator = self::USE_SL_NONE) { $this->di = $di; $this->name = $name; $this->parameters = $parameters; - if (in_array($useServiceManager, array(self::USE_SM_BEFORE_DI, self::USE_SM_AFTER_DI, self::USE_SM_NONE))) { - $this->useServiceManager = $useServiceManager; + if (in_array($useServiceLocator, array(self::USE_SL_BEFORE_DI, self::USE_SL_AFTER_DI, self::USE_SL_NONE))) { + $this->useServiceLocator = $useServiceLocator; } // since we are using this in a proxy-fashion, localize state @@ -40,25 +64,29 @@ public function __construct(Di $di, $name, array $parameters = array(), $useServ $this->instanceManager = $this->di->instanceManager; } - - public function createService(ServiceManager $serviceManager) + /** + * @param ServiceLocatorInterface $serviceLocator + * @return object + */ + public function createService(ServiceLocatorInterface $serviceLocator) { - $this->serviceManager = $serviceManager; + $this->serviceLocator = $serviceLocator; return $this->get($this->name, $this->parameters, true); } /** * Override, as we want it to use the functionality defined in the proxy * - * @param string $name - * @param array $params + * @param string $name + * @param array $params * @return object + * @throws Exception\InvalidServiceNameException */ public function get($name, array $params = array()) { // allow this di service to get dependencies from the service locator BEFORE trying di - if ($this->useServiceManager == self::USE_SM_BEFORE_DI && $this->serviceManager->has($name)) { - return $this->serviceManager->get($name); + if ($this->useServiceLocator == self::USE_SL_BEFORE_DI && $this->serviceLocator->has($name)) { + return $this->serviceLocator->get($name); } try { @@ -69,8 +97,8 @@ public function get($name, array $params = array()) } catch (DiClassNotFoundException $e) { // allow this di service to get dependencies from the service locator AFTER trying di - if ($this->useServiceManager == self::USE_SM_AFTER_DI && $this->serviceManager->has($name)) { - return $this->serviceManager->get($name); + if ($this->useServiceLocator == self::USE_SL_AFTER_DI && $this->serviceLocator->has($name)) { + return $this->serviceLocator->get($name); } else { throw new Exception\InvalidServiceNameException( sprintf('Service %s was not found in this DI instance', $name), diff --git a/src/Di/DiServiceInitializer.php b/src/Di/DiServiceInitializer.php index 83cba78b..30242d81 100644 --- a/src/Di/DiServiceInitializer.php +++ b/src/Di/DiServiceInitializer.php @@ -4,7 +4,7 @@ use Zend\ServiceManager\InitializerInterface, - Zend\ServiceManager\ServiceManager, + Zend\ServiceManager\ServiceLocatorInterface, Zend\ServiceManager\Exception, Zend\Di\Di, Zend\Di\Exception\ClassNotFoundException as DiClassNotFoundException; @@ -14,13 +14,13 @@ class DiServiceInitializer extends Di implements InitializerInterface protected $di = null; protected $diInstanceManagerProxy = null; - protected $serviceManager = null; + protected $serviceLocator = null; - public function __construct(Di $di, ServiceManager $serviceManager, DiInstanceManagerProxy $diImProxy = null) + public function __construct(Di $di, ServiceLocatorInterface $serviceLocator, DiInstanceManagerProxy $diImProxy = null) { $this->di = $di; - $this->serviceManager = $serviceManager; - $this->diInstanceManagerProxy = ($diImProxy) ?: new DiInstanceManagerProxy($di->instanceManager(), $serviceManager); + $this->serviceLocator = $serviceLocator; + $this->diInstanceManagerProxy = ($diImProxy) ?: new DiInstanceManagerProxy($di->instanceManager(), $serviceLocator); } public function initialize($instance) diff --git a/src/Exception/InstanceNotCreatedException.php b/src/Exception/ServiceNotCreatedException.php similarity index 52% rename from src/Exception/InstanceNotCreatedException.php rename to src/Exception/ServiceNotCreatedException.php index ca6d450e..68b35449 100644 --- a/src/Exception/InstanceNotCreatedException.php +++ b/src/Exception/ServiceNotCreatedException.php @@ -4,6 +4,6 @@ use Zend\ServiceManager\Exception; -class InstanceNotCreatedException extends \RuntimeException implements Exception +class ServiceNotCreatedException extends \RuntimeException implements Exception { } diff --git a/src/FactoryInterface.php b/src/FactoryInterface.php index 9d33e854..42cc96d0 100644 --- a/src/FactoryInterface.php +++ b/src/FactoryInterface.php @@ -4,5 +4,5 @@ interface FactoryInterface { - public function createService(ServiceManager $serviceManager); + public function createService(ServiceLocatorInterface $serviceLocator); } \ No newline at end of file diff --git a/src/ServiceManager.php b/src/ServiceManager.php index 62aacd40..ba13b737 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -28,7 +28,7 @@ class ServiceManager implements ServiceLocatorInterface protected $factories = array(); /** - * @var Closure|InstanceFactoryInterface[] + * @var Closure|AbstractFactoryInterface[] */ protected $abstractFactories = array(); @@ -62,7 +62,7 @@ class ServiceManager implements ServiceLocatorInterface /** * @var bool Track whether not ot throw exceptions during create() */ - protected $createThrowException = true; + protected $throwExceptionInCreate = true; /** * @param ConfigurationInterface $configuration @@ -91,6 +91,24 @@ public function getAllowOverride() return $this->allowOverride; } + /** + * @param bool $throwExceptionInCreate + * @return ServiceManager + */ + public function setThrowExceptionInCreate($throwExceptionInCreate) + { + $this->throwExceptionInCreate = $throwExceptionInCreate; + return $this; + } + + /** + * @return bool + */ + public function getThrowExceptionInCreate() + { + return $this->throwExceptionInCreate; + } + /** * @param $name * @param $invokableClass @@ -120,6 +138,12 @@ public function setFactory($name, $factory, $shared = true) { $name = $this->canonicalizeName($name); + if (!is_string($factory) && !$factory instanceof FactoryInterface && !is_callable($factory)) { + throw new Exception\InvalidArgumentException( + 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' + ); + } + if ($this->allowOverride === false && $this->has($name)) { throw new Exception\InvalidServiceNameException( 'A service by this name or alias already exists and cannot be overridden, please use an alternate name.' @@ -137,6 +161,12 @@ public function setFactory($name, $factory, $shared = true) */ public function addAbstractFactory($factory, $topOfStack = true) { + if (!is_string($factory) && !$factory instanceof AbstractFactoryInterface && !is_callable($factory)) { + throw new Exception\InvalidArgumentException( + 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' + ); + } + if ($topOfStack) { array_unshift($this->abstractFactories, $factory); } else { @@ -149,12 +179,18 @@ public function addAbstractFactory($factory, $topOfStack = true) * @param $initializer * @throws Exception\InvalidArgumentException */ - public function addInitializer($initializer) + public function addInitializer($initializer, $topOfStack = true) { if (!is_callable($initializer) && !$initializer instanceof InitializerInterface) { throw new Exception\InvalidArgumentException('$initializer should be callable.'); } - $this->initializers[] = $initializer; + + if ($topOfStack) { + array_unshift($this->initializers, $initializer); + } else { + array_push($this->initializers, $initializer); + } + return $this; } /** @@ -211,14 +247,10 @@ public function setShared($name, $isShared) * @param array $params * @return mixed */ - public function get($name) + public function get($name, $usePeeringServiceManagers = true) { - if (is_array($name)) { - list($cName, $rName) = $name; - } else { - $cName = $this->canonicalizeName($name);; - $rName = $name; - } + $cName = $this->canonicalizeName($name); + $rName = $name; if ($this->hasAlias($cName)) { do { @@ -230,6 +262,14 @@ public function get($name) if (isset($this->instances[$cName])) { $instance = $this->instances[$cName]; + } elseif ($usePeeringServiceManagers) { + foreach ($this->peeringServiceManagers as $peeringServiceManager) { + try { + $instance = $peeringServiceManager->get($name); + } catch (Exception\ServiceNotCreatedException $e) { + continue; + } + } } if (!$instance) { @@ -246,7 +286,7 @@ public function get($name) /** * @param $cName * @return false|object - * @throws Exception\InstanceNotCreatedException + * @throws Exception\ServiceNotCreatedException * @throws Exception\InvalidServiceNameException */ public function create($name) @@ -268,17 +308,17 @@ public function create($name) } if (!$instance && isset($this->factories[$cName])) { - $source = $this->factories[$cName]; - if (is_string($source) && class_exists($source, true)) { - $source = new $source; - $this->factories[$cName] = $source; + $factory = $this->factories[$cName]; + if (is_string($factory) && class_exists($factory, true)) { + $factory = new $factory; + $this->factories[$cName] = $factory; } - if ($source instanceof FactoryInterface) { - $instance = $this->createServiceViaCallback(array($source, 'createService'), $cName, $rName); - } elseif (is_callable($source)) { - $instance = $this->createServiceViaCallback($source, $cName, $rName); + if ($factory instanceof FactoryInterface) { + $instance = $this->createServiceViaCallback(array($factory, 'createService'), $cName, $rName); + } elseif (is_callable($factory)) { + $instance = $this->createServiceViaCallback($factory, $cName, $rName); } else { - throw new Exception\InstanceNotCreatedException(sprintf( + throw new Exception\ServiceNotCreatedException(sprintf( 'While attempting to create %s%s an invalid factory was registered for this instance type.', $cName, ($rName ? '(alias: ' . $rName . ')' : '') @@ -287,38 +327,30 @@ public function create($name) } if (!$instance && !empty($this->abstractFactories)) { - foreach ($this->abstractFactories as $index => $abstractSource) { + foreach ($this->abstractFactories as $index => $abstractFactory) { // support factories as strings - if (is_string($abstractSource)) { - $this->abstractFactories[$index] = $abstractSource = new $abstractSource; + if (is_string($abstractFactory) && class_exists($abstractFactory, true)) { + $this->abstractFactories[$index] = $abstractFactory = new $abstractFactory; } - if ($abstractSource instanceof AbstractFactoryInterface) { - $instance = $this->createServiceViaCallback(array($abstractSource, 'createServiceWithName'), $cName, $rName); - } elseif (is_callable($abstractSource)) { - $instance = $this->createServiceViaCallback($abstractSource, $cName, $rName); + if ($abstractFactory instanceof AbstractFactoryInterface) { + $instance = $this->createServiceViaCallback(array($abstractFactory, 'createServiceWithName'), $cName, $rName); + } elseif (is_callable($abstractFactory)) { + $instance = $this->createServiceViaCallback($abstractFactory, $cName, $rName); + } else { + throw new Exception\ServiceNotCreatedException(sprintf( + 'While attempting to create %s%s an abstract factory could not produce a valid instance.', + $cName, + ($rName ? '(alias: ' . $rName . ')' : '') + )); } if (is_object($instance)) { break; } } - if (!$instance) { - throw new Exception\InstanceNotCreatedException(sprintf( - 'While attempting to create %s%s an abstract factory could not produce a valid instance.', - $cName, - ($rName ? '(alias: ' . $rName . ')' : '') - )); - } } - if (!$instance && $this->peeringServiceManagers) { - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - $peeringServiceManager->createThrowException = false; - $instance = $peeringServiceManager->get($rName ?: $cName); - } - } - - if ($this->createThrowException == true && $instance === false) { - throw new Exception\InstanceNotCreatedException(sprintf( + if ($this->throwExceptionInCreate == true && $instance === false) { + throw new Exception\ServiceNotCreatedException(sprintf( 'No valid instance was found for %s%s', $cName, ($rName ? '(alias: ' . $rName . ')' : '') @@ -341,16 +373,42 @@ public function create($name) * @param $nameOrAlias * @return bool */ - public function has($nameOrAlias) + public function has($nameOrAlias, $usePeeringServiceManagers = true) { - $nameOrAlias = $this->canonicalizeName($nameOrAlias); + if (is_array($nameOrAlias)) { + list($cName, $rName) = $nameOrAlias; + } else { + $cName = $this->canonicalizeName($nameOrAlias); + $rName = $cName; + } - return ( - isset($this->invokableClasses[$nameOrAlias]) - || isset($this->factories[$nameOrAlias]) - || isset($this->aliases[$nameOrAlias]) - || isset($this->instances[$nameOrAlias]) + $has = ( + isset($this->invokableClasses[$cName]) + || isset($this->factories[$cName]) + || isset($this->aliases[$cName]) + || isset($this->instances[$cName]) ); + + if ($has) { + return true; + } + + // check abstract factories + foreach ($this->abstractFactories as $abstractFactory) { + if ($abstractFactory->canCreateServiceWithName($cName, $rName)) { + return true; + } + } + + if ($usePeeringServiceManagers) { + foreach ($this->peeringServiceManagers as $peeringServiceManager) { + if ($peeringServiceManager->has($rName)) { + return true; + } + } + } + + return false; } /** @@ -362,10 +420,14 @@ public function has($nameOrAlias) */ public function setAlias($alias, $nameOrAlias) { + if (!is_string($alias) || !is_string($nameOrAlias)) { + throw new Exception\InvalidServiceNameException('Service or alias names must be strings.'); + } + $alias = $this->canonicalizeName($alias); $nameOrAlias = $this->canonicalizeName($nameOrAlias); - if (!is_string($alias) || $alias == '') { + if ($alias == '' || $nameOrAlias == '') { throw new Exception\InvalidServiceNameException('Invalid service name alias'); } @@ -397,22 +459,14 @@ public function hasAlias($alias) */ public function createScopedServiceManager($peering = self::SCOPE_PARENT) { - $instanceManager = new ServiceManager(); + $scopedServiceManager = new ServiceManager(); if ($peering == self::SCOPE_PARENT) { - $instanceManager->registerPeerInstanceManager($this); + $scopedServiceManager->peeringServiceManagers[] = $this; } if ($peering == self::SCOPE_CHILD) { - $this->registerPeerInstanceManager($instanceManager); + $this->peeringServiceManagers[] = $scopedServiceManager; } - return $instanceManager; - } - - /** - * @param ServiceManager $instanceManager - */ - public function registerPeerInstanceManager(ServiceManager $instanceManager) - { - $this->peeringServiceManagers[] = $instanceManager; + return $scopedServiceManager; } /** @@ -428,7 +482,7 @@ protected function canonicalizeName($name) * @param callable $callable * @param $cName * @param $rName - * @throws Exception\InstanceNotCreatedException + * @throws Exception\ServiceNotCreatedException * @throws Exception\CircularDependencyFoundException * @return object */ @@ -444,7 +498,7 @@ protected function createServiceViaCallback($callable, $cName, $rName) $circularDependencyResolver[spl_object_hash($this) . '-' . $cName] = true; $instance = call_user_func($callable, $this, $cName, $rName); if ($instance === null) { - throw new Exception\InstanceNotCreatedException('The factory was called but did not return an instance.'); + throw new Exception\ServiceNotCreatedException('The factory was called but did not return an instance.'); } unset($circularDependencyResolver[spl_object_hash($this) . '-' . $cName]); diff --git a/src/Validator.php b/src/Validator.php deleted file mode 100644 index e69de29b..00000000 diff --git a/test/ServiceManagerTest.php b/test/ServiceManagerTest.php index 3f67eb5e..703d0228 100644 --- a/test/ServiceManagerTest.php +++ b/test/ServiceManagerTest.php @@ -2,7 +2,8 @@ namespace ZendTest\ServiceManager; -use Zend\ServiceManager\ServiceManager; +use Zend\ServiceManager\ServiceManager, + Zend\ServiceManager\Configuration; class ServiceManagerTest extends \PHPUnit_Framework_TestCase { @@ -17,6 +18,16 @@ public function setup() $this->serviceManager = new ServiceManager; } + /** + * @covers Zend\ServiceManager\ServiceManager::__construct + */ + public function testConstructorConfiguration() + { + $config = new Configuration(array('services' => array('foo' => 'bar'))); + $serviceManager = new ServiceManager($config); + $this->assertEquals('bar', $serviceManager->get('foo')); + } + /** * @covers Zend\ServiceManager\ServiceManager::setAllowOverride * @covers Zend\ServiceManager\ServiceManager::getAllowOverride @@ -29,6 +40,18 @@ public function testAllowOverride() $this->assertTrue($this->serviceManager->getAllowOverride()); } + /** + * @covers Zend\ServiceManager\ServiceManager::setThrowExceptionInCreate + * @covers Zend\ServiceManager\ServiceManager::getThrowExceptionInCreate + */ + public function testThrowExceptionInCreate() + { + $this->assertTrue($this->serviceManager->getThrowExceptionInCreate()); + $ret = $this->serviceManager->setThrowExceptionInCreate(false); + $this->assertSame($this->serviceManager, $ret); + $this->assertFalse($this->serviceManager->getThrowExceptionInCreate()); + } + /** * @covers Zend\ServiceManager\ServiceManager::setInvokableClass */ @@ -58,29 +81,44 @@ public function testSetFactoryThrowsExceptionOnDuplicate() } /** - * @covers Zend\ServiceManager\ServiceManager::addAbstractSource - * @todo Implement testAddAbstractSource(). + * @covers Zend\ServiceManager\ServiceManager::addAbstractFactory */ - public function testAddAbstractSource() + public function testAddAbstractFactory() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); + + $ret = $this->serviceManager->addAbstractFactory(new TestAsset\FooAbstractFactory()); + $this->assertSame($this->serviceManager, $ret); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::addAbstractFactory + */ + public function testAddAbstractFactoryThrowsExceptionOnInvalidFactory() + { + $this->setExpectedException('Zend\ServiceManager\Exception\InvalidArgumentException'); + $this->serviceManager->addAbstractFactory(10); } /** * @covers Zend\ServiceManager\ServiceManager::addInitializer - * @todo Implement testAddInitializer(). */ public function testAddInitializer() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $ret = $this->serviceManager->addInitializer(new TestAsset\FooInitializer()); + $this->assertSame($this->serviceManager, $ret); } + /** + * @covers Zend\ServiceManager\ServiceManager::addInitializer + */ + public function testAddInitializerThrowsExceptionOnInvalidInitializer() + { + $this->setExpectedException('Zend\ServiceManager\Exception\InvalidArgumentException'); + $this->serviceManager->addInitializer(5); + } + + /** * @covers Zend\ServiceManager\ServiceManager::setService */ @@ -111,26 +149,96 @@ public function testSetSharedThrowsExceptionOnUnregisteredService() /** * @covers Zend\ServiceManager\ServiceManager::get - * @todo Implement testGet(). */ public function testGet() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->serviceManager->setService('foo', 'bar'); + $this->assertEquals('bar', $this->serviceManager->get('foo')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::get + */ + public function testGetThrowsExceptionOnUnknownService() + { + $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotCreatedException'); + $this->assertEquals('bar', $this->serviceManager->get('foo')); + } + + + /** + * @covers Zend\ServiceManager\ServiceManager::get + */ + public function testGetWithAlias() + { + $this->serviceManager->setService('foo', 'bar'); + $this->serviceManager->setAlias('baz', 'foo'); + $this->assertEquals('bar', $this->serviceManager->get('baz')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::get + */ + public function testGetWithScopedContainer() + { + $this->serviceManager->setService('foo', 'bar'); + $scopedServiceManager = $this->serviceManager->createScopedServiceManager(); + $this->assertEquals('bar', $scopedServiceManager->get('foo')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::create + */ + public function testCreateWithInvokableClass() + { + $this->serviceManager->setInvokableClass('foo', 'ZendTest\ServiceManager\TestAsset\Foo'); + $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::create + */ + public function testCreateWithFactoryInstance() + { + $this->serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\FooFactory'); + $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::create + */ + public function testCreateWithCallableFactory() + { + $this->serviceManager->setFactory('foo', function () { return new TestAsset\Foo; }); + $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); } /** * @covers Zend\ServiceManager\ServiceManager::create - * @todo Implement testCreate(). */ - public function testCreate() + public function testCreateWithAbstractFactory() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); + $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::create + */ + public function testCreateWithCallableAbstractFactory() + { + $this->serviceManager->addAbstractFactory(function () { return new TestAsset\Foo; }); + $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); + } + + public function testCreateWithInitializerObject() + { + $this->serviceManager->addInitializer(new TestAsset\FooInitializer(array('foo' => 'bar'))); + $this->serviceManager->setFactory('foo', function () { + return new \stdClass(); + }); + $obj = $this->serviceManager->get('foo'); + $this->assertEquals('bar', $obj->foo); } /** @@ -145,7 +253,6 @@ public function testHas() /** * @covers Zend\ServiceManager\ServiceManager::setAlias - * @todo Implement testSetAlias(). */ public function testSetAlias() { @@ -155,38 +262,71 @@ public function testSetAlias() } /** - * @covers Zend\ServiceManager\ServiceManager::hasAlias - * @todo Implement testHasAlias(). + * @covers Zend\ServiceManager\ServiceManager::setAlias */ - public function testHasAlias() + public function testSetAliasThrowsExceptionOnInvalidAliasName() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); + $this->serviceManager->setAlias(5, 10); } /** - * @covers Zend\ServiceManager\ServiceManager::createScopedServiceManager - * @todo Implement testCreateScopedServiceManager(). + * @covers Zend\ServiceManager\ServiceManager::setAlias */ - public function testCreateScopedServiceManager() + public function testSetAliasThrowsExceptionOnEmptyAliasName() + { + $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); + $this->serviceManager->setAlias('', 'foo'); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::setAlias + */ + public function testSetAliasThrowsExceptionOnDuplicateAlias() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->serviceManager->setService('foo', 'bar'); + $this->serviceManager->setAlias('baz', 'foo'); + + $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); + $this->serviceManager->setAlias('baz', 'foo'); } /** - * @covers Zend\ServiceManager\ServiceManager::registerPeerInstanceManager - * @todo Implement testRegisterPeerInstanceManager(). + * @covers Zend\ServiceManager\ServiceManager::setAlias */ - public function testRegisterPeerInstanceManager() + public function testSetAliasThrowExceptionOnServiceNotFound() { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); + $this->serviceManager->setAlias('foo', 'bar'); } + + /** + * @covers Zend\ServiceManager\ServiceManager::hasAlias + */ + public function testHasAlias() + { + $this->assertFalse($this->serviceManager->hasAlias('foo')); + + $this->serviceManager->setService('bar', 'baz'); + $this->serviceManager->setAlias('foo', 'bar'); + $this->assertTrue($this->serviceManager->hasAlias('foo')); + } + + /** + * @covers Zend\ServiceManager\ServiceManager::createScopedServiceManager + */ + public function testCreateScopedServiceManager() + { + $this->serviceManager->setService('foo', 'bar'); + $scopedServiceManager = $this->serviceManager->createScopedServiceManager(); + $this->assertNotSame($this->serviceManager, $scopedServiceManager); + $this->assertFalse($scopedServiceManager->has('foo', false)); + + $this->assertContains($this->serviceManager, $this->readAttribute($scopedServiceManager, 'peeringServiceManagers')); + + // test child scoped + $childScopedServiceManager = $this->serviceManager->createScopedServiceManager(ServiceManager::SCOPE_CHILD); + $this->assertContains($childScopedServiceManager, $this->readAttribute($this->serviceManager, 'peeringServiceManagers')); + } + } diff --git a/test/TestAsset/Foo.php b/test/TestAsset/Foo.php new file mode 100644 index 00000000..4dfa6aac --- /dev/null +++ b/test/TestAsset/Foo.php @@ -0,0 +1,8 @@ +var = $var; + } + } + + public function initialize($instance) + { + if ($this->var) { + list($key, $value) = each($this->var); + $instance->{$key} = $value; + } + } +} From 5098fd262578e3f0a825c77444cf9ae9b54aadeb Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Tue, 1 May 2012 10:24:26 -0500 Subject: [PATCH 2/3] Test for ServiceManager's Zend\Di integration [zen-33] --- src/Di/DiServiceFactory.php | 1 - test/Di/DiAbstractServiceFactoryTest.php | 14 +++++++ test/Di/DiServiceFactoryTest.php | 11 +++++ test/Di/DiServiceInitializerTest.php | 52 ++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/Di/DiAbstractServiceFactoryTest.php create mode 100644 test/Di/DiServiceFactoryTest.php create mode 100644 test/Di/DiServiceInitializerTest.php diff --git a/src/Di/DiServiceFactory.php b/src/Di/DiServiceFactory.php index 673090d5..28155d5d 100644 --- a/src/Di/DiServiceFactory.php +++ b/src/Di/DiServiceFactory.php @@ -2,7 +2,6 @@ namespace Zend\ServiceManager\Di; - use Zend\ServiceManager\FactoryInterface, Zend\ServiceManager\ServiceLocatorInterface, Zend\ServiceManager\Exception, diff --git a/test/Di/DiAbstractServiceFactoryTest.php b/test/Di/DiAbstractServiceFactoryTest.php new file mode 100644 index 00000000..877cd705 --- /dev/null +++ b/test/Di/DiAbstractServiceFactoryTest.php @@ -0,0 +1,14 @@ +mockDi = $this->getMock('Zend\Di\Di', array('injectDependencies')); + $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); + $this->mockDiInstanceManagerProxy = new DiInstanceManagerProxy( + $this->getMock('Zend\Di\InstanceManager'), + $this->mockServiceLocator + ); + $this->diServiceInitializer = new DiServiceInitializer( + $this->mockDi, + $this->mockServiceLocator, + $this->mockDiInstanceManagerProxy + ); + + } + + /** + * @covers Zend\ServiceManager\Di\DiServiceInitializer::initialize + */ + public function testInitialize() + { + $instance = new \stdClass(); + + // test di is called with proper instance + $this->mockDi->expects($this->once())->method('injectDependencies')->with($instance); + + $this->diServiceInitializer->initialize($instance); + } + +} From ee23691a0abcdca4b1a6671ab9d8afc675ba37dd Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Tue, 1 May 2012 11:29:12 -0500 Subject: [PATCH 3/3] Improved unit tests for ServiceManager [zen-33] --- src/Di/DiServiceInitializer.php | 23 +++++++++-- test/Di/DiAbstractServiceFactoryTest.php | 49 ++++++++++++++++++++-- test/Di/DiServiceFactoryTest.php | 52 +++++++++++++++++++++++- 3 files changed, 117 insertions(+), 7 deletions(-) diff --git a/src/Di/DiServiceInitializer.php b/src/Di/DiServiceInitializer.php index 30242d81..d168e381 100644 --- a/src/Di/DiServiceInitializer.php +++ b/src/Di/DiServiceInitializer.php @@ -2,7 +2,6 @@ namespace Zend\ServiceManager\Di; - use Zend\ServiceManager\InitializerInterface, Zend\ServiceManager\ServiceLocatorInterface, Zend\ServiceManager\Exception, @@ -11,11 +10,26 @@ class DiServiceInitializer extends Di implements InitializerInterface { - + /** + * @var Di + */ protected $di = null; + + /** + * @var DiInstanceManagerProxy + */ protected $diInstanceManagerProxy = null; + + /** + * @var ServiceLocatorInterface + */ protected $serviceLocator = null; + /** + * @param \Zend\Di\Di $di + * @param \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator + * @param null|DiInstanceManagerProxy $diImProxy + */ public function __construct(Di $di, ServiceLocatorInterface $serviceLocator, DiInstanceManagerProxy $diImProxy = null) { $this->di = $di; @@ -23,6 +37,9 @@ public function __construct(Di $di, ServiceLocatorInterface $serviceLocator, DiI $this->diInstanceManagerProxy = ($diImProxy) ?: new DiInstanceManagerProxy($di->instanceManager(), $serviceLocator); } + /** + * @param $instance + */ public function initialize($instance) { $instanceManager = $this->di->instanceManager; @@ -30,7 +47,7 @@ public function initialize($instance) try { $this->di->injectDependencies($instance); $this->di->instanceManager = $instanceManager; - } catch (Exception $e) { + } catch (\Exception $e) { $this->di->instanceManager = $instanceManager; throw $e; } diff --git a/test/Di/DiAbstractServiceFactoryTest.php b/test/Di/DiAbstractServiceFactoryTest.php index 877cd705..dcd4726b 100644 --- a/test/Di/DiAbstractServiceFactoryTest.php +++ b/test/Di/DiAbstractServiceFactoryTest.php @@ -3,12 +3,55 @@ namespace ZendTest\ServiceManager\Di; use Zend\ServiceManager\Di\DiAbstractServiceFactory, - Zend\ServiceManager\Di\DiInstanceManagerProxy; +Zend\ServiceManager\Di\DiInstanceManagerProxy; class DiAbstractServiceFactoryTest extends \PHPUnit_Framework_TestCase { - public function testCreateServiceWithName() {} - public function testCanCreateServiceWithName() {} + /** + * @var DiAbstractServiceFactory + */ + protected $diAbstractServiceFactory = null; + /**@#+ + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $mockDi = null; + protected $mockServiceLocator = null; + /**@#-*/ + + protected $fooInstance = null; + + public function setup() + { + $instanceManager = new \Zend\Di\InstanceManager(); + $instanceManager->addSharedInstance($this->fooInstance = new \stdClass(), 'foo'); + $this->mockDi = $this->getMock('Zend\Di\Di', array(), array(null, $instanceManager)); + $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); + $this->diAbstractServiceFactory = new DiAbstractServiceFactory( + $this->mockDi + ); + } + + + /** + * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::__construct + */ + public function testConstructor() + { + $instance = new DiAbstractServiceFactory( + $this->getMock('Zend\Di\Di') + ); + $this->assertInstanceOf('Zend\ServiceManager\Di\DiAbstractServiceFactory', $instance); + } + + /** + * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::createServiceWithName + * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::get + */ + public function testCreateServiceWithName() + { + $foo = $this->diAbstractServiceFactory->createServiceWithName($this->mockServiceLocator, 'foo'); + $this->assertEquals($this->fooInstance, $foo); + } } diff --git a/test/Di/DiServiceFactoryTest.php b/test/Di/DiServiceFactoryTest.php index 0c6c22e1..6808bf07 100644 --- a/test/Di/DiServiceFactoryTest.php +++ b/test/Di/DiServiceFactoryTest.php @@ -7,5 +7,55 @@ class DiServiceFactoryTest extends \PHPUnit_Framework_TestCase { - public function testCreateService() {} + + protected $diServiceFactory = null; + + /**@#+ + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $mockDi = null; + protected $mockServiceLocator = null; + /**@#-*/ + + protected $fooInstance = null; + + public function setup() + { + $instanceManager = new \Zend\Di\InstanceManager(); + $instanceManager->addSharedInstanceWithParameters( + $this->fooInstance = new \stdClass(), + 'foo', + array('bar' => 'baz') + ); + $this->mockDi = $this->getMock('Zend\Di\Di', array(), array(null, $instanceManager)); + $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); + $this->diServiceFactory = new DiServiceFactory( + $this->mockDi, + 'foo', + array('bar' => 'baz') + ); + } + + /** + * @covers Zend\ServiceManager\Di\DiServiceFactory::__construct + */ + public function testConstructor() + { + $instance = new DiServiceFactory( + $this->getMock('Zend\Di\Di'), + 'string', + array('foo' => 'bar') + ); + $this->assertInstanceOf('Zend\ServiceManager\Di\DiServiceFactory', $instance); + } + + /** + * @covers Zend\ServiceManager\Di\DiServiceFactory::createService + * @covers Zend\ServiceManager\Di\DiServiceFactory::get + */ + public function testCreateService() + { + $foo = $this->diServiceFactory->createService($this->mockServiceLocator); + $this->assertEquals($this->fooInstance, $foo); + } }