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