1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19:
20: App::uses('Dispatcher', 'Routing');
21: App::uses('CakeTestCase', 'TestSuite');
22: App::uses('Router', 'Routing');
23: App::uses('CakeRequest', 'Network');
24: App::uses('CakeResponse', 'Network');
25: App::uses('Helper', 'View');
26: App::uses('CakeEvent', 'Event');
27:
28: 29: 30: 31: 32:
33: class ControllerTestDispatcher extends Dispatcher {
34:
35: 36: 37: 38: 39:
40: public $testController = null;
41:
42: 43: 44: 45: 46:
47: public $loadRoutes = true;
48:
49: 50: 51: 52: 53:
54: protected function _getController($request, $response) {
55: if ($this->testController === null) {
56: $this->testController = parent::_getController($request, $response);
57: }
58: $this->testController->helpers = array_merge(array('InterceptContent'), $this->testController->helpers);
59: $this->testController->setRequest($request);
60: $this->testController->response = $this->response;
61: foreach ($this->testController->Components->attached() as $component) {
62: $object = $this->testController->Components->{$component};
63: if (isset($object->response)) {
64: $object->response = $response;
65: }
66: if (isset($object->request)) {
67: $object->request = $request;
68: }
69: }
70: return $this->testController;
71: }
72:
73: 74: 75: 76: 77:
78: protected function _loadRoutes() {
79: parent::_loadRoutes();
80: if (!$this->loadRoutes) {
81: Router::reload();
82: }
83: }
84:
85: }
86:
87: 88: 89: 90: 91:
92: class InterceptContentHelper extends Helper {
93:
94: 95: 96: 97: 98:
99: public function afterRender($viewFile) {
100: $this->_View->assign('__view_no_layout__', $this->_View->fetch('content'));
101: $this->_View->Helpers->unload('InterceptContent');
102: }
103:
104: }
105:
106: 107: 108: 109: 110:
111: abstract class ControllerTestCase extends CakeTestCase {
112:
113: 114: 115: 116: 117:
118: public $controller = null;
119:
120: 121: 122: 123: 124:
125: public $autoMock = true;
126:
127: 128: 129: 130: 131:
132: public $loadRoutes = true;
133:
134: 135: 136: 137: 138:
139: public $vars = null;
140:
141: 142: 143: 144: 145:
146: public $view = null;
147:
148: 149: 150: 151: 152:
153: public $contents = null;
154:
155: 156: 157: 158: 159:
160: public $result = null;
161:
162: 163: 164: 165: 166:
167: public $headers = null;
168:
169: 170: 171: 172: 173: 174: 175:
176: protected $_dirtyController = false;
177:
178: 179: 180: 181: 182: 183: 184: 185: 186:
187: public function __call($name, $arguments) {
188: if ($name == 'testAction') {
189: return call_user_func_array(array($this, '_testAction'), $arguments);
190: }
191: throw new BadMethodCallException("Method '{$name}' does not exist.");
192: }
193:
194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213:
214: protected function _testAction($url = '', $options = array()) {
215: $this->vars = $this->result = $this->view = $this->contents = $this->headers = null;
216:
217: $options = array_merge(array(
218: 'data' => array(),
219: 'method' => 'POST',
220: 'return' => 'result'
221: ), $options);
222:
223: $restore = array('get' => $_GET, 'post' => $_POST);
224:
225: $_SERVER['REQUEST_METHOD'] = strtoupper($options['method']);
226: if (is_array($options['data'])) {
227: if (strtoupper($options['method']) == 'GET') {
228: $_GET = $options['data'];
229: $_POST = array();
230: } else {
231: $_POST = $options['data'];
232: $_GET = array();
233: }
234: }
235: $request = $this->getMock('CakeRequest', array('_readInput'), array($url));
236:
237: if (is_string($options['data'])) {
238: $request->expects($this->any())
239: ->method('_readInput')
240: ->will($this->returnValue($options['data']));
241: }
242:
243: $Dispatch = new ControllerTestDispatcher();
244: foreach (Router::$routes as $route) {
245: if ($route instanceof RedirectRoute) {
246: $route->response = $this->getMock('CakeResponse', array('send'));
247: }
248: }
249: $Dispatch->loadRoutes = $this->loadRoutes;
250: $Dispatch->parseParams(new CakeEvent('ControllerTestCase', $Dispatch, array('request' => $request)));
251: if (!isset($request->params['controller']) && Router::currentRoute()) {
252: $this->headers = Router::currentRoute()->response->header();
253: return;
254: }
255: if ($this->_dirtyController) {
256: $this->controller = null;
257: }
258:
259: $plugin = empty($request->params['plugin']) ? '' : Inflector::camelize($request->params['plugin']) . '.';
260: if ($this->controller === null && $this->autoMock) {
261: $this->generate($plugin . Inflector::camelize($request->params['controller']));
262: }
263: $params = array();
264: if ($options['return'] == 'result') {
265: $params['return'] = 1;
266: $params['bare'] = 1;
267: $params['requested'] = 1;
268: }
269: $Dispatch->testController = $this->controller;
270: $Dispatch->response = $this->getMock('CakeResponse', array('send'));
271: $this->result = $Dispatch->dispatch($request, $Dispatch->response, $params);
272: $this->controller = $Dispatch->testController;
273: $this->vars = $this->controller->viewVars;
274: $this->contents = $this->controller->response->body();
275: if (isset($this->controller->View)) {
276: $this->view = $this->controller->View->fetch('__view_no_layout__');
277: }
278: $this->_dirtyController = true;
279: $this->headers = $Dispatch->response->header();
280:
281: $_GET = $restore['get'];
282: $_POST = $restore['post'];
283:
284: return $this->{$options['return']};
285: }
286:
287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307:
308: public function generate($controller, $mocks = array()) {
309: list($plugin, $controller) = pluginSplit($controller);
310: if ($plugin) {
311: App::uses($plugin . 'AppController', $plugin . '.Controller');
312: $plugin .= '.';
313: }
314: App::uses($controller . 'Controller', $plugin . 'Controller');
315: if (!class_exists($controller . 'Controller')) {
316: throw new MissingControllerException(array(
317: 'class' => $controller . 'Controller',
318: 'plugin' => substr($plugin, 0, -1)
319: ));
320: }
321: ClassRegistry::flush();
322:
323: $mocks = array_merge_recursive(array(
324: 'methods' => array('_stop'),
325: 'models' => array(),
326: 'components' => array()
327: ), (array)$mocks);
328:
329: list($plugin, $name) = pluginSplit($controller);
330: $_controller = $this->getMock($name . 'Controller', $mocks['methods'], array(), '', false);
331: $_controller->name = $name;
332: $request = $this->getMock('CakeRequest');
333: $response = $this->getMock('CakeResponse', array('_sendHeader'));
334: $_controller->__construct($request, $response);
335:
336: $config = ClassRegistry::config('Model');
337: foreach ($mocks['models'] as $model => $methods) {
338: if (is_string($methods)) {
339: $model = $methods;
340: $methods = true;
341: }
342: if ($methods === true) {
343: $methods = array();
344: }
345: ClassRegistry::init($model);
346: list($plugin, $name) = pluginSplit($model);
347: $config = array_merge((array)$config, array('name' => $model));
348: $_model = $this->getMock($name, $methods, array($config));
349: ClassRegistry::removeObject($name);
350: ClassRegistry::addObject($name, $_model);
351: }
352:
353: foreach ($mocks['components'] as $component => $methods) {
354: if (is_string($methods)) {
355: $component = $methods;
356: $methods = true;
357: }
358: if ($methods === true) {
359: $methods = array();
360: }
361: list($plugin, $name) = pluginSplit($component, true);
362: $componentClass = $name . 'Component';
363: App::uses($componentClass, $plugin . 'Controller/Component');
364: if (!class_exists($componentClass)) {
365: throw new MissingComponentException(array(
366: 'class' => $componentClass
367: ));
368: }
369: $_component = $this->getMock($componentClass, $methods, array(), '', false);
370: $_controller->Components->set($name, $_component);
371: }
372:
373: $_controller->constructClasses();
374: $this->_dirtyController = false;
375:
376: $this->controller = $_controller;
377: return $this->controller;
378: }
379:
380: }
381: