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