AppController.php
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Auth' => array(
'authorize' => array('Controller')
),
'Session'
);
}
PostsController.php
<?php
App::uses('AppController', 'Controller');
class PostsController extends AppController {
public function isAuthorized() {
return $this->Auth->user('role') == 'admin';
}
public function add() {
$this->set('some_var', true);
}
}
PostsControllerTest.php
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public function setUp() {
parent::setUp();
CakeSession::write('Auth.User', array(
'id' => 2,
'username' => 'joe_bloggs',
'role' => 'user',
'created' => '2013-05-17 10:00:00',
'modified' => '2013-05-17 10:00:00'
));
}
public function testAddWhileLoggedInAsNonAdminFails() {
$this->testAction('/posts/add/', array('method' => 'get'));
$this->assertTrue($this->vars['some_var']);
}
public function tearDown() {
parent::tearDown();
CakeSession::destroy();
}
}
现在,“testAddWhileLoggedInAsNonAdminFails”测试通过了。它应该失败。问题是重定向不会退出/停止模拟请求。
我可以通过修改“AppController.php”和“PostsControllerTest.php”来解决问题:
修改后的AppController.php
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Auth' => array(
'authorize' => array('Controller'),
// ***** THE FOLLOWING LINE IS NEW *****
'unauthorizedRedirect' => false
),
'Session'
);
}
修改后的PostsControllerTest.php
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public function setUp() {
parent::setUp();
CakeSession::write('Auth.User', array(
'id' => 2,
'username' => 'joe_bloggs',
'role' => 'user',
'created' => '2013-05-17 10:00:00',
'modified' => '2013-05-17 10:00:00'
));
}
// ***** THE FOLLOWING 3 LINES ARE NEW *****
/**
* @expectedException ForbiddenException
*/
public function testAddWhileLoggedInAsNonAdminFails() {
$this->testAction('/posts/add/', array('method' => 'get'));
}
public function tearDown() {
parent::tearDown();
CakeSession::destroy();
}
}
此解决方案的问题在于它也修改了真实网站的行为。我正在寻找一种方法,在运行测试时将Auth组件的unauthorizedRedirect
属性设置为false
。我怎么能这样做?
答案 0 :(得分:2)
更改代码的行为以使测试正常工作并不是一个好主意。
这个问题的正确答案是,它不是一个非常好的问题,你真正应该做的是分别测试每个功能。
对于isAuthorized函数,您应该执行:
<?php
class PostsControllerTest extends ControllerTestCase {
public function testIsAuthorized() {
$Posts = $this->generate('Posts');
$user = array('role' => 'admin');
$this->assertTrue($Posts->isAuthorized($user));
$anotherUser = array('role' => 'saboteur');
$this->assertFalse($Posts->isAuthorized($user));
}
public function testAdd() {
$this->testAction('/posts/add/', array('method' => 'get'));
$this->assertTrue($this->vars['some_var']);
}
}
单元测试背后的核心概念是将您的应用程序分解为可能的最小部分,并单独测试每个部分。一旦你完成了单元测试,就可以进行涵盖多个功能的集成测试,但很多项目都没有达到那个阶段,这没关系。重定向问题可能很有意思,但您可以按照in this blog post所述模拟出controller :: redirect。它有点旧但仍然有用。
答案 1 :(得分:0)
测试包含redirect()和其他代码的操作时 重定向通常是重定向时返回的好主意。 原因是redirect()在测试中被模拟,并且确实如此 不像正常那样退出。而不是你的代码退出,它会 继续在重定向后运行代码。
它确切地描述了您的问题。
我还没有对此进行测试但是尝试了一下,手册说控制器在使用ControllerTestCase时已经被嘲笑了,所以你应该可以期待它:
$this->controller->expects($this->at(0))
->method('redirect')
->with('/your-expected-input');
看一下ControllerTestCase类可能会揭示控制器是如何被精确地模拟和设置的。或者你可以回到常规的CakeTestCase并自己设置控制器模拟。
另一个替代方法是扩展您想要测试的控制器并覆盖redirect()方法,而不是调用父级,而是将第一个arg设置为类似Controller :: $ redirectUrl的属性。在您的操作调用之后,您可以断言属性值。但是这仍然需要您在控制器中的重定向调用后返回。在使用ControllerTestCase时,这也不会起作用,因为它会模拟你的覆盖方法。