PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Cake/TestSuite/ControllerTestCase.php

https://bitbucket.org/udeshika/fake_twitter
PHP | 366 lines | 183 code | 32 blank | 151 comment | 26 complexity | b2dd5cad4eca078a1f53267b524b32d1 MD5 | raw file
  1. <?php
  2. /**
  3. * ControllerTestCase file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
  15. * @package Cake.TestSuite
  16. * @since CakePHP(tm) v 2.0
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. App::uses('Dispatcher', 'Routing');
  20. App::uses('CakeTestCase', 'TestSuite');
  21. App::uses('Router', 'Routing');
  22. App::uses('CakeRequest', 'Network');
  23. App::uses('CakeResponse', 'Network');
  24. App::uses('Helper', 'View');
  25. /**
  26. * ControllerTestDispatcher class
  27. *
  28. * @package Cake.TestSuite
  29. */
  30. class ControllerTestDispatcher extends Dispatcher {
  31. /**
  32. * The controller to use in the dispatch process
  33. *
  34. * @var Controller
  35. */
  36. public $testController = null;
  37. /**
  38. * Use custom routes during tests
  39. *
  40. * @var boolean
  41. */
  42. public $loadRoutes = true;
  43. /**
  44. * Returns the test controller
  45. *
  46. * @return Controller
  47. */
  48. function _getController($request, $response) {
  49. if ($this->testController === null) {
  50. $this->testController = parent::_getController($request, $response);
  51. }
  52. $this->testController->helpers = array_merge(array('InterceptContent'), $this->testController->helpers);
  53. $this->testController->setRequest($request);
  54. $this->testController->response = $this->response;
  55. foreach ($this->testController->Components->attached() as $component) {
  56. $object = $this->testController->Components->{$component};
  57. if (isset($object->response)) {
  58. $object->response = $response;
  59. }
  60. }
  61. if (isset($object->request)) {
  62. $object->request = $request;
  63. }
  64. return $this->testController;
  65. }
  66. /**
  67. * Loads routes and resets if the test case dictates it should
  68. *
  69. * @return void
  70. */
  71. protected function _loadRoutes() {
  72. parent::_loadRoutes();
  73. if (!$this->loadRoutes) {
  74. Router::reload();
  75. }
  76. }
  77. }
  78. /**
  79. * InterceptContentHelper class
  80. *
  81. * @package Cake.TestSuite
  82. */
  83. class InterceptContentHelper extends Helper {
  84. /**
  85. * Intercepts and stores the contents of the view before the layout is rendered
  86. *
  87. * @param string $viewFile The view file
  88. */
  89. public function afterRender($viewFile) {
  90. $this->_View->_viewNoLayout = $this->_View->output;
  91. $this->_View->Helpers->unload('InterceptContent');
  92. }
  93. }
  94. /**
  95. * ControllerTestCase class
  96. *
  97. * @package Cake.TestSuite
  98. */
  99. abstract class ControllerTestCase extends CakeTestCase {
  100. /**
  101. * The controller to test in testAction
  102. *
  103. * @var Controller
  104. */
  105. public $controller = null;
  106. /**
  107. * Automatically mock controllers that aren't mocked
  108. *
  109. * @var boolean
  110. */
  111. public $autoMock = true;
  112. /**
  113. * Use custom routes during tests
  114. *
  115. * @var boolean
  116. */
  117. public $loadRoutes = true;
  118. /**
  119. * The resulting view vars of the last testAction call
  120. *
  121. * @var array
  122. */
  123. public $vars = null;
  124. /**
  125. * The resulting rendered view of the last testAction call
  126. *
  127. * @var string
  128. */
  129. public $view = null;
  130. /**
  131. * The resulting rendered layout+view of the last testAction call
  132. *
  133. * @var string
  134. */
  135. public $contents = null;
  136. /**
  137. * The returned result of the dispatch (requestAction), if any
  138. *
  139. * @var string
  140. */
  141. public $result = null;
  142. /**
  143. * The headers that would have been sent by the action
  144. *
  145. * @var string
  146. */
  147. public $headers = null;
  148. /**
  149. * Flag for checking if the controller instance is dirty.
  150. * Once a test has been run on a controller it should be rebuilt
  151. * to clean up properties.
  152. *
  153. * @var boolean
  154. */
  155. private $__dirtyController = false;
  156. /**
  157. * Used to enable calling ControllerTestCase::testAction() without the testing
  158. * framework thinking that it's a test case
  159. *
  160. * @param string $name The name of the function
  161. * @param array $arguments Array of arguments
  162. * @return Function
  163. */
  164. public function __call($name, $arguments) {
  165. if ($name == 'testAction') {
  166. return call_user_func_array(array($this, '_testAction'), $arguments);
  167. }
  168. }
  169. /**
  170. * Lets you do functional tests of a controller action.
  171. *
  172. * ### Options:
  173. *
  174. * - `data` Will be used as the request data. If the `method` is GET,
  175. * data will be used a GET params. If the `method` is POST, it will be used
  176. * as POST data. By setting `$options['data']` to a string, you can simulate XML or JSON
  177. * payloads to your controllers allowing you to test REST webservices.
  178. * - `method` POST or GET. Defaults to POST.
  179. * - `return` Specify the return type you want. Choose from:
  180. * - `vars` Get the set view variables.
  181. * - `view` Get the rendered view, without a layout.
  182. * - `contents` Get the rendered view including the layout.
  183. * - `result` Get the return value of the controller action. Useful
  184. * for testing requestAction methods.
  185. *
  186. * @param string $url The url to test
  187. * @param array $options See options
  188. */
  189. protected function _testAction($url = '', $options = array()) {
  190. $this->vars = $this->result = $this->view = $this->contents = $this->headers = null;
  191. $options = array_merge(array(
  192. 'data' => array(),
  193. 'method' => 'POST',
  194. 'return' => 'result'
  195. ), $options);
  196. $_SERVER['REQUEST_METHOD'] = strtoupper($options['method']);
  197. if (is_array($options['data'])) {
  198. if (strtoupper($options['method']) == 'GET') {
  199. $_GET = $options['data'];
  200. $_POST = array();
  201. } else {
  202. $_POST = $options['data'];
  203. $_GET = array();
  204. }
  205. }
  206. $request = $this->getMock('CakeRequest', array('_readInput'), array($url));
  207. if (is_string($options['data'])) {
  208. $request->expects($this->any())
  209. ->method('_readInput')
  210. ->will($this->returnValue($options['data']));
  211. }
  212. $Dispatch = new ControllerTestDispatcher();
  213. foreach (Router::$routes as $route) {
  214. if ($route instanceof RedirectRoute) {
  215. $route->response = $this->getMock('CakeResponse', array('send'));
  216. }
  217. }
  218. $Dispatch->loadRoutes = $this->loadRoutes;
  219. $request = $Dispatch->parseParams($request);
  220. if (!isset($request->params['controller'])) {
  221. $this->headers = Router::currentRoute()->response->header();
  222. return;
  223. }
  224. if ($this->__dirtyController) {
  225. $this->controller = null;
  226. }
  227. $plugin = empty($request->params['plugin']) ? '' : Inflector::camelize($request->params['plugin']) . '.';
  228. if ($this->controller === null && $this->autoMock) {
  229. $this->generate($plugin . Inflector::camelize($request->params['controller']));
  230. }
  231. $params = array();
  232. if ($options['return'] == 'result') {
  233. $params['return'] = 1;
  234. $params['bare'] = 1;
  235. $params['requested'] = 1;
  236. }
  237. $Dispatch->testController = $this->controller;
  238. $Dispatch->response = $this->getMock('CakeResponse', array('send'));
  239. $this->result = $Dispatch->dispatch($request, $Dispatch->response, $params);
  240. $this->controller = $Dispatch->testController;
  241. $this->vars = $this->controller->viewVars;
  242. $this->contents = $this->controller->response->body();
  243. if (isset($this->controller->View)) {
  244. $this->view = $this->controller->View->_viewNoLayout;
  245. }
  246. $this->__dirtyController = true;
  247. $this->headers = $Dispatch->response->header();
  248. return $this->{$options['return']};
  249. }
  250. /**
  251. * Generates a mocked controller and mocks any classes passed to `$mocks`. By
  252. * default, `_stop()` is stubbed as is sending the response headers, so to not
  253. * interfere with testing.
  254. *
  255. * ### Mocks:
  256. *
  257. * - `methods` Methods to mock on the controller. `_stop()` is mocked by default
  258. * - `models` Models to mock. Models are added to the ClassRegistry so they any
  259. * time they are instantiated the mock will be created. Pass as key value pairs
  260. * with the value being specific methods on the model to mock. If `true` or
  261. * no value is passed, the entire model will be mocked.
  262. * - `components` Components to mock. Components are only mocked on this controller
  263. * and not within each other (i.e., components on components)
  264. *
  265. * @param string $controller Controller name
  266. * @param array $mocks List of classes and methods to mock
  267. * @return Controller Mocked controller
  268. */
  269. public function generate($controller, $mocks = array()) {
  270. list($plugin, $controller) = pluginSplit($controller);
  271. if ($plugin) {
  272. App::uses($plugin . 'AppController', $plugin . '.Controller');
  273. $plugin .= '.';
  274. }
  275. App::uses($controller . 'Controller', $plugin . 'Controller');
  276. if (!class_exists($controller.'Controller')) {
  277. throw new MissingControllerException(array(
  278. 'class' => $controller . 'Controller',
  279. 'plugin' => substr($plugin, 0, -1)
  280. ));
  281. }
  282. ClassRegistry::flush();
  283. $mocks = array_merge_recursive(array(
  284. 'methods' => array('_stop'),
  285. 'models' => array(),
  286. 'components' => array()
  287. ), (array)$mocks);
  288. list($plugin, $name) = pluginSplit($controller);
  289. $_controller = $this->getMock($name.'Controller', $mocks['methods'], array(), '', false);
  290. $_controller->name = $name;
  291. $request = $this->getMock('CakeRequest');
  292. $response = $this->getMock('CakeResponse', array('_sendHeader'));
  293. $_controller->__construct($request, $response);
  294. $config = ClassRegistry::config('Model');
  295. foreach ($mocks['models'] as $model => $methods) {
  296. if (is_string($methods)) {
  297. $model = $methods;
  298. $methods = true;
  299. }
  300. if ($methods === true) {
  301. $methods = array();
  302. }
  303. ClassRegistry::init($model);
  304. list($plugin, $name) = pluginSplit($model);
  305. $config = array_merge((array)$config, array('name' => $model));
  306. $_model = $this->getMock($name, $methods, array($config));
  307. ClassRegistry::removeObject($name);
  308. ClassRegistry::addObject($name, $_model);
  309. }
  310. foreach ($mocks['components'] as $component => $methods) {
  311. if (is_string($methods)) {
  312. $component = $methods;
  313. $methods = true;
  314. }
  315. if ($methods === true) {
  316. $methods = array();
  317. }
  318. list($plugin, $name) = pluginSplit($component, true);
  319. $componentClass = $name . 'Component';
  320. App::uses($componentClass, $plugin . 'Controller/Component');
  321. if (!class_exists($componentClass)) {
  322. throw new MissingComponentException(array(
  323. 'class' => $componentClass
  324. ));
  325. }
  326. $_component = $this->getMock($componentClass, $methods, array(), '', false);
  327. $_controller->Components->set($name, $_component);
  328. }
  329. $_controller->constructClasses();
  330. $this->__dirtyController = false;
  331. $this->controller = $_controller;
  332. return $this->controller;
  333. }
  334. }