[TASK] Fix for unit tests to change singletons and reset again
authorChristian Kuhn <lolli@schwarzbu.ch>
Sun, 9 Sep 2012 23:02:59 +0000 (01:02 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sun, 9 Sep 2012 23:42:35 +0000 (01:42 +0200)
TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance() is a method
for unit tests to inject singleton mocks for classes that are
instantiated with makeInstance. purgeInstances() can be used to reset all
registered singletons, so makeInstance() creates new objects after that.
purgeInstances() can change the behaviour of tests that are executed
afterwards, because *all* registered singletons are reset. Currently the
helper methods for singletons around makeInstance() are not able to get
the list of registered singletons, and reset them to the previous list.

The patch introduces method getSingletonInstances() that returns a list
of all registered singletons (used in setUp()), and method
resetSingletonInstances() that resets registered singletons to a given
stored list (used in tearDown()). This way it is possible to fiddle in
tests with purgeInstances() without introducing side effects to other
tests.

All unit tests that used purgeInstances() are adapted to take care
of re constitution of changed objects this way.

Change-Id: I19dc869423a537226bb019e227d84b6f74fe9afc
Resolves: #40780
Releases: 6.0
Reviewed-on: http://review.typo3.org/14487
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
12 files changed:
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Tests/Unit/DataHandler/DataHandlerTest.php
typo3/sysext/core/Tests/Unit/Extension/ExtensionManagerTest.php
typo3/sysext/core/Tests/Unit/Resource/Driver/LocalDriverTest.php
typo3/sysext/core/Tests/Unit/Resource/FactoryTest.php
typo3/sysext/core/Tests/Unit/Resource/FileTest.php
typo3/sysext/core/Tests/Unit/Resource/FolderTest.php
typo3/sysext/core/Tests/Unit/Resource/StorageTest.php
typo3/sysext/core/Tests/Unit/Resource/Utility/FileExtensionFilterTest.php
typo3/sysext/core/Tests/Unit/Utility/File/ExtendedFileUtilityTest.php
typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php
typo3/sysext/core/Tests/Unit/Utility/MailUtilityTest.php

index 1bfa713..02de64b 100644 (file)
@@ -4187,7 +4187,11 @@ Connection: close
         * If this function is called multiple times for the same $className,
         * makeInstance will return the last set instance.
         *
-        * Warning: This is _not_ a public API method and must not be used in own extensions!
+        * Warning:
+        * This is NOT a public API method and must not be used in own extensions!
+        * This methods exists mostly for unit tests to inject a mock of a singleton class.
+        * If you use this, make sure to always combine this with getSingletonInstances()
+        * and resetSingletonInstances() in setUp() and tearDown() of the test class.
         *
         * @see makeInstance
         * @param string $className
@@ -4201,6 +4205,43 @@ Connection: close
        }
 
        /**
+        * Set a group of singleton instances. Similar to setSingletonInstance(),
+        * but multiple instances can be set.
+        *
+        * Warning:
+        * This is NOT a public API method and must not be used in own extensions!
+        * This method is usually only used in tests to restore the list of singletons in
+        * tearDown(), that was backed up with getSingletonInstances() in setUp() and
+        * manipulated in tests with setSingletonInstance()
+        *
+        * @internal
+        * @param array $newSingletonInstances $className => $object
+        * @return void
+        */
+       static public function resetSingletonInstances(array $newSingletonInstances) {
+               static::$singletonInstances = array();
+               foreach ($newSingletonInstances as $className => $instance) {
+                       static::setSingletonInstance($className, $instance);
+               }
+       }
+
+       /**
+        * Get all currently registered singletons
+        *
+        * Warning:
+        * This is NOT a public API method and must not be used in own extensions!
+        * This method is usually only used in tests in setUp() to fetch the list of
+        * currently registered singletons, if this list is manipulated with
+        * setSingletonInstance() in tests.
+        *
+        * @internal
+        * @return array $className => $object
+        */
+       static public function getSingletonInstances() {
+               return static::$singletonInstances;
+       }
+
+       /**
         * Sets the instance of a non-singleton class to be returned by makeInstance.
         *
         * If this function is called multiple times for the same $className,
@@ -4210,7 +4251,7 @@ Connection: close
         * Warning: This is a helper method for unit tests. Do not call this directly in production code!
         *
         * @see makeInstance
-        * @throws InvalidArgumentException if class extends t3lib_Singleton
+        * @throws \InvalidArgumentException if class extends t3lib_Singleton
         * @param string $className
         * @param object $instance
         * @return void
@@ -4230,7 +4271,7 @@ Connection: close
         * Checks that $className is non-empty and that $instance is an instance of
         * $className.
         *
-        * @throws InvalidArgumentException if $className is empty or if $instance is no instance of $className
+        * @throws \InvalidArgumentException if $className is empty or if $instance is no instance of $className
         * @param string $className a class name
         * @param object $instance an object
         * @return void
index 510c58f..189f636 100644 (file)
@@ -56,6 +56,11 @@ class DataHandlerTest extends \tx_phpunit_testcase {
        protected $databaseBackup = NULL;
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * @var \TYPO3\CMS\Core\DataHandler\DataHandler
         */
        private $fixture;
@@ -66,6 +71,7 @@ class DataHandlerTest extends \tx_phpunit_testcase {
        private $backEndUser;
 
        public function setUp() {
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                $this->databaseBackup = $GLOBALS['TYPO3_DB'];
                $this->backEndUser = $this->getMock('TYPO3\\CMS\\Core\\Authentication\\BackendUserAuthentication');
                $this->fixture = new \TYPO3\CMS\Core\DataHandler\DataHandler();
@@ -73,7 +79,7 @@ class DataHandlerTest extends \tx_phpunit_testcase {
        }
 
        public function tearDown() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
                $GLOBALS['TYPO3_DB'] = $this->databaseBackup;
                unset($this->fixture->BE_USER, $this->fixture, $this->backEndUser, $this->databaseBackup);
        }
index 79d47aa..26206d1 100644 (file)
@@ -35,6 +35,11 @@ namespace TYPO3\CMS\Core\Tests\Unit\Extension;
 class ExtensionManagerTest extends \tx_phpunit_testcase {
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * Enable backup of global and system variables
         *
         * @var boolean
@@ -72,6 +77,7 @@ class ExtensionManagerTest extends \tx_phpunit_testcase {
                        'TYPO3_LOADED_EXT' => serialize($GLOBALS['TYPO3_LOADED_EXT'])
                );
                $this->testFilesToDelete = array();
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
        }
 
        public function tearDown() {
@@ -82,7 +88,7 @@ class ExtensionManagerTest extends \tx_phpunit_testcase {
                foreach ($this->testFilesToDelete as $absoluteFileName) {
                        \TYPO3\CMS\Core\Utility\GeneralUtility::unlink_tempfile($absoluteFileName);
                }
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
        }
 
        /**
index e391bc5..a96289c 100644 (file)
@@ -41,6 +41,11 @@ require_once dirname(__FILE__) . '/Fixtures/LocalDriverFilenameFilter.php';
 class LocalDriverTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * @var array
         */
        static private $testDirs = array();
@@ -49,11 +54,13 @@ class LocalDriverTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
                parent::setUp();
                // use a mocked file repository to avoid updating the index when doing property update tests
                $mockedRepository = $this->getMock('TYPO3\\CMS\\Core\\Resource\\FileRepository');
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository', $mockedRepository);
        }
 
        public function tearDown() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
                parent::tearDown();
        }
 
index 681b949..a6a04f2 100644 (file)
@@ -36,6 +36,11 @@ require_once 'vfsStream/vfsStream.php';
 class FactoryTest extends \Tx_Phpunit_TestCase {
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * @var \TYPO3\CMS\Core\Resource\ResourceFactory
         */
        private $fixture;
@@ -46,11 +51,12 @@ class FactoryTest extends \Tx_Phpunit_TestCase {
        private $objectCreated = FALSE;
 
        public function setUp() {
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                $this->fixture = new \TYPO3\CMS\Core\Resource\ResourceFactory();
        }
 
        protected function tearDown() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
        }
 
        /**********************************
index 9e8a6c2..09173a2 100644 (file)
@@ -36,10 +36,20 @@ require_once 'vfsStream/vfsStream.php';
  */
 class FileTest extends \Tx_Phpunit_TestCase {
 
-       protected function tearDown() {
+       /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       public function setUp() {
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
        }
 
+       public function tearDown() {
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
+       }
+
        /**
         * @return \TYPO3\CMS\Core\Resource\File
         */
index a4f35f6..0a67b0f 100644 (file)
@@ -38,14 +38,20 @@ require_once 'vfsStream/vfsStream.php';
  */
 class FolderTest extends \Tx_Phpunit_TestCase {
 
+       /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
        private $basedir = 'basedir';
 
        public function setUp() {
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                \vfsStream::setup($this->basedir);
        }
 
        protected function tearDown() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
        }
 
        protected function createFolderFixture($path, $name, $mockedStorage = NULL) {
index 6665ef6..29815ab 100644 (file)
@@ -36,10 +36,26 @@ require_once 'vfsStream/vfsStream.php';
 class StorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * @var \TYPO3\CMS\Core\Resource\ResourceStorage
         */
        private $fixture;
 
+       public function setUp() {
+               parent::setUp();
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+       }
+
+       public function tearDown() {
+               parent::tearDown();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
+       }
+
        /**
         * Prepare fixture
         *
index 0c0c446..25bf2f6 100644 (file)
@@ -37,6 +37,11 @@ namespace TYPO3\CMS\Core\Tests\Unit\Resource\Utility;
 class FileExtensionFilterTest extends \Tx_Phpunit_TestCase {
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * @var \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter
         */
        protected $filter;
@@ -63,6 +68,7 @@ class FileExtensionFilterTest extends \Tx_Phpunit_TestCase {
                $this->filter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
                $this->tceMainMock = $this->getMock('TYPO3\\CMS\\Core\\DataHandler\\DataHandler', array('deleteAction'), array());
                $this->fileFactoryMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceFactory', array('getFileReferenceObject'), array());
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory', $this->fileFactoryMock);
        }
 
@@ -74,7 +80,7 @@ class FileExtensionFilterTest extends \Tx_Phpunit_TestCase {
                unset($this->tceMainMock);
                unset($this->parameters);
                unset($this->filter);
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
        }
 
        /**
index 426be9a..09cefba 100644 (file)
@@ -33,6 +33,24 @@ namespace TYPO3\CMS\Core\Tests\Unit\Utility\File;
 class ExtendedFileUtilityTest extends \tx_phpunit_testcase {
 
        /**
+        * @var boolean Enable backup of global and system variables
+        */
+       protected $backupGlobals = TRUE;
+
+       /**
+        * Exclude TYPO3_DB from backup/ restore of $GLOBALS
+        * because resource types cannot be handled during serializing
+        *
+        * @var array
+        */
+       protected $backupGlobalsBlacklist = array('TYPO3_DB');
+
+       /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * @var \TYPO3\CMS\Core\Utility\File\ExtendedFileUtility
         */
        protected $fileProcessor;
@@ -91,6 +109,8 @@ class ExtendedFileUtilityTest extends \tx_phpunit_testcase {
                $this->fileProcessor->init($GLOBALS['FILEMOUNTS'], $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
                $this->fileProcessor->init_actionPerms($GLOBALS['BE_USER']->getFileoperationPermissions());
                $this->fileProcessor->dontCheckForUnique = 1;
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
        }
 
        /**
@@ -103,6 +123,7 @@ class ExtendedFileUtilityTest extends \tx_phpunit_testcase {
                        }
                }
                $this->objectsToTearDown = array();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
        }
 
        /**
index f70d05e..3bb7353 100644 (file)
@@ -49,8 +49,17 @@ class GeneralUtilityTest extends \tx_phpunit_testcase {
         */
        protected $backupGlobalsBlacklist = array('TYPO3_DB');
 
+       /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       public function setUp() {
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+       }
+
        public function tearDown() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
        }
 
        ///////////////////////////
@@ -3509,6 +3518,44 @@ class GeneralUtilityTest extends \tx_phpunit_testcase {
 
        /**
         * @test
+        */
+       public function getSingletonInstancesContainsPreviouslySetSingletonInstance() {
+               $instance = $this->getMock('TYPO3\\CMS\\Core\\SingletonInterface');
+               $instanceClassName = get_class($instance);
+               \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance($instanceClassName, $instance);
+               $registeredSingletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+               $this->assertArrayHasKey($instanceClassName, $registeredSingletonInstances);
+               $this->assertSame($registeredSingletonInstances[$instanceClassName], $instance);
+       }
+
+       /**
+        * @test
+        */
+       public function resetSingletonInstancesResetsPreviouslySetInstance() {
+               $instance = $this->getMock('TYPO3\\CMS\\Core\\SingletonInterface');
+               $instanceClassName = get_class($instance);
+               \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance($instanceClassName, $instance);
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances(array());
+               $registeredSingletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+               $this->assertArrayNotHasKey($instanceClassName, $registeredSingletonInstances);
+       }
+
+       /**
+        * @test
+        */
+       public function resetSingletonInstancesSetsGivenInstance() {
+               $instance = $this->getMock('TYPO3\\CMS\\Core\\SingletonInterface');
+               $instanceClassName = get_class($instance);
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances(
+                       array($instanceClassName => $instance)
+               );
+               $registeredSingletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
+               $this->assertArrayHasKey($instanceClassName, $registeredSingletonInstances);
+               $this->assertSame($registeredSingletonInstances[$instanceClassName], $instance);
+       }
+
+       /**
+        * @test
         * @expectedException InvalidArgumentException
         */
        public function addInstanceForEmptyClassNameThrowsException() {
index 77e0784..75b49b3 100644 (file)
@@ -34,6 +34,11 @@ namespace TYPO3\CMS\Core\Tests\Unit\Utility;
 class MailUtilityTest extends \tx_phpunit_testcase {
 
        /**
+        * @var array A backup of registered singleton instances
+        */
+       protected $singletonInstances = array();
+
+       /**
         * backed-up TYPO3_CONF_VARS SC_OPTIONS
         *
         * @var array
@@ -48,12 +53,13 @@ class MailUtilityTest extends \tx_phpunit_testcase {
        private $callUserFunctionBackup = array();
 
        public function setUp() {
+               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                $this->scOptionsBackup = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'];
                $this->callUserFunctionBackup = $GLOBALS['T3_VAR']['callUserFunction'];
        }
 
        public function tearDown() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
                $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'] = $this->scOptionsBackup;
                $GLOBALS['T3_VAR']['callUserFunction'] = $this->callUserFunctionBackup;
        }