Index: tests/t3lib/t3lib_divTest.php
===================================================================
--- tests/t3lib/t3lib_divTest.php	(revision 9642)
+++ tests/t3lib/t3lib_divTest.php	(working copy)
@@ -32,7 +32,6 @@
  * @subpackage t3lib
  */
 class t3lib_divTest extends tx_phpunit_testcase {
-
 	/**
 	 * Enable backup of global and system variables
 	 *
@@ -48,6 +47,10 @@
 	 */
 	protected $backupGlobalsBlacklist = array('TYPO3_DB');
 
+	public function tearDown() {
+		t3lib_div::purgeInstances();
+	}
+
 
 	///////////////////////////////
 	// Tests concerning validIP
@@ -1816,12 +1819,21 @@
 	}
 
 
-	//////////////////////////////////
-	// Tests concerning makeInstance
-	//////////////////////////////////
+	/////////////////////////////////////////////////////////////////////////////////////
+	// Tests concerning makeInstance, setSingletonInstance, addInstance, purgeInstances
+	/////////////////////////////////////////////////////////////////////////////////////
 
 	/**
 	 * @test
+	 *
+	 * @expectedException InvalidArgumentException
+	 */
+	public function makeInstanceWithEmptyClassNameThrowsException() {
+		t3lib_div::makeInstance('');
+	}
+
+	/**
+	 * @test
 	 */
 	public function makeInstanceReturnsClassInstance() {
 		$className = get_class($this->getMock('foo'));
@@ -1886,5 +1898,178 @@
 			t3lib_div::makeInstance($className)
 		);
 	}
+
+	/**
+	 * @test
+	 */
+	public function makeInstanceCalledTwoTimesForSingletonClassWithPurgeInstancesInbetweenReturnsDifferentInstances() {
+		$className = get_class($this->getMock('t3lib_Singleton'));
+
+		$instance = t3lib_div::makeInstance($className);
+		t3lib_div::purgeInstances();
+
+		$this->assertNotSame(
+			$instance,
+			t3lib_div::makeInstance($className)
+		);
+	}
+
+	/**
+	 * @test
+	 *
+	 * @expectedException InvalidArgumentException
+	 */
+	public function setSingletonInstanceForEmptyClassNameThrowsException() {
+		$instance = $this->getMock('t3lib_Singleton');
+
+		t3lib_div::setSingletonInstance('', $instance);
+	}
+
+	/**
+	 * @test
+	 *
+	 * @expectedException InvalidArgumentException
+	 */
+	public function setSingletonInstanceForClassThatIsNoSubclassOfProvidedClassThrowsException() {
+		$instance = $this->getMock('t3lib_Singleton', array('foo'));
+		$singletonClassName = get_class($this->getMock('t3lib_Singleton'));
+
+		t3lib_div::setSingletonInstance($singletonClassName, $instance);
+	}
+
+	/**
+	 * @test
+	 */
+	public function setSingletonInstanceMakesMakeInstanceReturnThatInstance() {
+		$instance = $this->getMock('t3lib_Singleton');
+		$singletonClassName = get_class($instance);
+
+		t3lib_div::setSingletonInstance($singletonClassName, $instance);
+
+		$this->assertSame(
+			$instance,
+			t3lib_div::makeInstance($singletonClassName)
+		);
+	}
+
+	/**
+	 * @test
+	 */
+	public function setSingletonInstanceCalledTwoTimesMakesMakeInstanceReturnLastSetInstance() {
+		$instance1 = $this->getMock('t3lib_Singleton');
+		$singletonClassName = get_class($instance1);
+		$instance2 = new $singletonClassName();
+
+		t3lib_div::setSingletonInstance($singletonClassName, $instance1);
+		t3lib_div::setSingletonInstance($singletonClassName, $instance2);
+
+		$this->assertSame(
+			$instance2,
+			t3lib_div::makeInstance($singletonClassName)
+		);
+	}
+
+	/**
+	 * @test
+	 *
+	 * @expectedException InvalidArgumentException
+	 */
+	public function addInstanceForEmptyClassNameThrowsException() {
+		$instance = $this->getMock('foo');
+
+		t3lib_div::addInstance('', $instance);
+	}
+
+	/**
+	 * @test
+	 *
+	 * @expectedException InvalidArgumentException
+	 */
+	public function addInstanceForClassThatIsNoSubclassOfProvidedClassThrowsException() {
+		$instance = $this->getMock('foo', array('bar'));
+		$singletonClassName = get_class($this->getMock('foo'));
+
+		t3lib_div::addInstance($singletonClassName, $instance);
+	}
+
+	/**
+	 * @test
+	 *
+	 * @expectedException InvalidArgumentException
+	 */
+	public function addInstanceWithSingletonInstanceThrowsException() {
+		$instance = $this->getMock('t3lib_Singleton');
+
+		t3lib_div::addInstance(get_class($instance), $instance);
+	}
+
+	/**
+	 * @test
+	 */
+	public function addInstanceMakesMakeInstanceReturnThatInstance() {
+		$instance = $this->getMock('foo');
+		$className = get_class($instance);
+
+		t3lib_div::addInstance($className, $instance);
+
+		$this->assertSame(
+			$instance,
+			t3lib_div::makeInstance($className)
+		);
+	}
+
+	/**
+	 * @test
+	 */
+	public function makeInstanceCalledTwoTimesAfterAddInstanceReturnTwoDifferentInstances() {
+		$instance = $this->getMock('foo');
+		$className = get_class($instance);
+
+		t3lib_div::addInstance($className, $instance);
+
+		$this->assertNotSame(
+			t3lib_div::makeInstance($className),
+			t3lib_div::makeInstance($className)
+		);
+	}
+
+	/**
+	 * @test
+	 */
+	public function addInstanceCalledTwoTimesMakesMakeInstanceReturnBothInstancesInAddingOrder() {
+		$instance1 = $this->getMock('foo');
+		$className = get_class($instance1);
+		t3lib_div::addInstance($className, $instance1);
+
+		$instance2 = new $className();
+		t3lib_div::addInstance($className, $instance2);
+
+		$this->assertSame(
+			$instance1,
+			t3lib_div::makeInstance($className),
+			'The first returned instance does not match the first added instance.'
+		);
+		$this->assertSame(
+			$instance2,
+			t3lib_div::makeInstance($className),
+			'The second returned instance does not match the second added instance.'
+		);
+	}
+
+	/**
+	 * @test
+	 */
+	public function purgeInstancesDropsAddedInstance() {
+		$instance = $this->getMock('foo');
+		$className = get_class($instance);
+
+		t3lib_div::addInstance($className, $instance);
+		t3lib_div::purgeInstances();
+
+		$this->assertNotSame(
+			$instance,
+			t3lib_div::makeInstance($className)
+		);
+	}
 }
 ?>
\ No newline at end of file
Index: t3lib/class.t3lib_div.php
===================================================================
--- t3lib/class.t3lib_div.php	(revision 9642)
+++ t3lib/class.t3lib_div.php	(working copy)
@@ -228,7 +228,6 @@
  * @subpackage t3lib
  */
 final class t3lib_div {
-
 		// Severity constants used by t3lib_div::sysLog()
 	const SYSLOG_SEVERITY_INFO = 0;
 	const SYSLOG_SEVERITY_NOTICE = 1;
@@ -236,6 +235,20 @@
 	const SYSLOG_SEVERITY_ERROR = 3;
 	const SYSLOG_SEVERITY_FATAL = 4;
 
+	/**
+	 * singleton instances returned by makeInstance, using the class names as
+	 * array keys
+	 *
+	 * @var array<t3lib_Singleton>
+	 */
+	static protected $singletonInstances = array();
+
+	/**
+	 * instances returned by makeInstance, using the class names as array keys
+	 *
+	 * @var array<array><object>
+	 */
+	static protected $nonSingletonInstances = array();
 
 	/*************************
 	 *
@@ -5362,36 +5375,40 @@
 	 * You can also pass arguments for a constructor:
 	 *	 t3lib_div::makeInstance('myClass', $arg1, $arg2,  ..., $argN)
 	 *
-	 * @param	string		Class name to instantiate
-	 * @return	object		A reference to the object
+	 * @param	string		$className
+	 * 			name of the class to instantiate, must not be empty
+	 *
+	 * @return	object		the created instance
 	 */
 	public static function makeInstance($className) {
-			// holds references of singletons
-		static $instances = array();
+		if ($className === '') {
+			throw new InvalidArgumentException('$className must not be empty.', 1288965219);
+		}
 
-			// Get final classname
-		$className = self::getClassName($className);
+		$finalClassName = self::getClassName($className);
 
-		if (isset($instances[$className])) {
-				// it's a singleton, get the existing instance
-			$instance = $instances[$className];
-		} else {
-			if (func_num_args() > 1) {
-					// getting the constructor arguments by removing this
-					// method's first argument (the class name)
-				$constructorArguments = func_get_args();
-				array_shift($constructorArguments);
+		if (isset(self::$singletonInstances[$finalClassName])) {
+			return self::$singletonInstances[$finalClassName];
+		}
 
-				$reflectedClass = new ReflectionClass($className);
-				$instance = $reflectedClass->newInstanceArgs($constructorArguments);
-			} else {
-				$instance = new $className;
-			}
+		if (isset(self::$nonSingletonInstances[$finalClassName])
+			&& !empty(self::$nonSingletonInstances[$finalClassName])
+		) {
+			return array_shift(self::$nonSingletonInstances[$finalClassName]);
+		}
 
-			if ($instance instanceof t3lib_Singleton) {
-					// it's a singleton, save the instance for later reuse
-				$instances[$className] = $instance;
-			}
+		if (func_num_args() > 1) {
+			$constructorArguments = func_get_args();
+			array_shift($constructorArguments);
+
+			$reflectedClass = new ReflectionClass($finalClassName);
+			$instance = $reflectedClass->newInstanceArgs($constructorArguments);
+		} else {
+			$instance = new $finalClassName;
+		}
+
+		if ($instance instanceof t3lib_Singleton) {
+			self::$singletonInstances[$finalClassName] = $instance;
 		}
 
 		return $instance;
@@ -5424,6 +5441,101 @@
 	}
 
 	/**
+	 * Sets the instance of a singleton class to be returned by makeInstance.
+	 *
+	 * If this function is called multiple times for the same $className,
+	 * makeInstance will return the last set instance.
+	 *
+	 * This function is intendend help with unit testing.
+	 *
+	 * @param string $className
+	 *        the name of the class to set, must not be empty
+	 * @param t3lib_Singleton $instance
+	 *        the instance to set, must be an instance of $className
+	 *
+	 * @return void
+	 *
+	 * @see makeInstance
+	 */
+	public function setSingletonInstance($className, t3lib_Singleton $instance) {
+		self::checkInstanceClassName($className, $instance);
+
+		self::$singletonInstances[$className] = $instance;
+	}
+
+	/**
+	 * Sets the instance of a non-singleton class to be returned by makeInstance.
+	 *
+	 * If this function is called multiple times for the same $className,
+	 * makeInstance will return the instances in the order in which they have
+	 * been added.
+	 *
+	 * This function is intendend help with unit testing.
+	 *
+	 * @param string $className
+	 *        the name of the class to set, must not be empty
+	 * @param object $instance
+	 *        the instance to set, must be an instance of $className
+	 *
+	 * @return void
+	 *
+	 * @see makeInstance
+	 */
+	public function addInstance($className, $instance) {
+		self::checkInstanceClassName($className, $instance);
+
+		if ($instance instanceof t3lib_Singleton) {
+			throw new InvalidArgumentException(
+				'$instance must not be an instance of t3lib_Singleton. ' .
+					'For setting singletons, please use setSingletonInstance.',
+				1288969325
+			);
+		}
+
+		if (!isset(self::$nonSingletonInstances[$className])) {
+			self::$nonSingletonInstances[$className] = array();
+		}
+		self::$nonSingletonInstances[$className][] = $instance;
+	}
+
+	/**
+	 * Checks that $className is non-empty and that $instance is an instance of
+	 * $className.
+	 *
+	 * @param string $className a class name
+	 * @param object $instance an object
+	 *
+	 * @throws InvalidArgumentException
+	 *         if $className is empty or if $instance is no instance of $className
+	 */
+	static protected function checkInstanceClassName($className, $instance) {
+		if ($className === '') {
+			throw new InvalidArgumentException('$className must not be empty.', 1288967479);
+		}
+		if (!($instance instanceof $className)) {
+			throw new InvalidArgumentException(
+				'$instance must be an instance of ' . $className . ', but actually is an instance of ' . get_class($instance) . '.',
+				1288967686
+			);
+		}
+	}
+
+	/**
+	 * Purges all instances returned by makeInstance.
+	 *
+	 * This function is most useful when called from tearDown in a testcase
+	 * to drop any instances that have been created by the tests.
+	 *
+	 * @return void
+	 *
+	 * @see makeInstance
+	 */
+	static public function purgeInstances() {
+		self::$singletonInstances = array();
+		self::$nonSingletonInstances = array();
+	}
+
+	/**
 	 * Find the best service and check if it works.
 	 * Returns object of the service class.
 	 *
@@ -6209,5 +6321,4 @@
 		echo $obContent;
 	}
 }
-
 ?>
\ No newline at end of file
Index: NEWS.txt
===================================================================
--- NEWS.txt	(revision 9642)
+++ NEWS.txt	(working copy)
@@ -142,6 +142,12 @@
 	  having no console like the IE
 	* ExtDirect is available in the frontend now (#15754):
 	  http://wiki.typo3.org/ExtDirect
+	* t3lib_div now provides two functions setSingletonInstance and addInstance
+	  that will set the objects to be returned by makeInstance. (#16267)
+	  This will allow unit tests to inject mocks into makeInstance.
+	  In addition, there now is a function purgeInstances that makes
+	  makeInstance return fresh instances (singleton as well as non-singleton).
+
 
 TypoScript
 ==========
