/** * Build a fake class dynamically that extends the desired class, * but will act more like a Friend class on a dynamically created mock. * This lets you use the mock methods in order to validate inputs and * return good, simulated values. * * By using the class renaming functionality of Renamer, the mock is * generated whenever you use the "new" keyword on the class we're * changing. Please consider restructuring your code to use some sort * of dependency injection since overriding "new" is an icky hack. * * Arguments for the callback, when used, should be like this: * function ($testObject, $newMockObject, $constructorArguments) * * @param string $type Name of class to mock * @param callback $callback Constructor callback for mock set up * @param array $methodsToKeep array to pass to getMockExceptMethods * @param boolean $callParent should the mock call the parent constructor */ public function stubWithMock($className, $callback = null, $methodsToKeep = array(), $callParent = false) { $myself = $this; // The test needs to be friended to have access to methods $testFriend = new Friend($myself); $mocker = function () use($className, $methodsToKeep, $myself) { return $myself->getMockExceptMethods($className, $methodsToKeep, array(), '', false); }; $mockDef = PHPToolsTestUtil::stubWithMock($mocker, $className, $methodsToKeep, $callParent); $mockDef->callback = function ($mock, $args) use($callback, $testFriend) { // Register this mock with the array of mock objects. // Due to the Friend's magic getter/setter, we can not use // $testFriend->mockObjects[] = $mock; $mocks = $testFriend->mockObjects; $mocks[] = $mock; $testFriend->mockObjects = $mocks; // Call the setup function if ($callback) { call_user_func($callback, $testFriend, $mock, $args); } }; return $mockDef->className; }