控制器代码
<?php
App::uses('AppController', 'Controller');
class PostsController extends AppController {
public function isAuthorized() {
return true;
}
public function edit($id = null) {
$this->autoRender = false;
if (!$this->Post->exists($id)) {
throw new NotFoundException(__('Invalid post'));
}
if ($this->Post->find('first', array(
'conditions' => array(
'Post.id' => $id,
'Post.user_id' => $this->Auth->user('id')
)
))) {
echo 'Username: ' . $this->Auth->user('username') . '<br>';
echo 'Created: ' . $this->Auth->user('created') . '<br>';
echo 'Modified: ' . $this->Auth->user('modified') . '<br>';
echo 'All:';
pr($this->Auth->user());
echo 'Modified: ' . $this->Auth->user('modified') . '<br>';
} else {
echo 'Unauthorized.';
}
}
}
Run Code Online (Sandbox Code Playgroud)
浏览器输出
Username: admin
Created: 2013-05-08 00:00:00
Modified: 2013-05-08 00:00:00
All:
Array
(
[id] => 1
[username] => admin
[created] => 2013-05-08 00:00:00
[modified] => 2013-05-08 00:00:00
)
Modified: 2013-05-08 00:00:00
Run Code Online (Sandbox Code Playgroud)
测试代码
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public $fixtures = array(
'app.post',
'app.user'
);
public function testEdit() {
$this->Controller = $this->generate('Posts', array(
'components' => array(
'Auth' => array('user')
)
));
$this->Controller->Auth->staticExpects($this->at(0))->method('user')->with('id')->will($this->returnValue(1));
$this->Controller->Auth->staticExpects($this->at(1))->method('user')->with('username')->will($this->returnValue('admin'));
$this->Controller->Auth->staticExpects($this->at(2))->method('user')->with('created')->will($this->returnValue('2013-05-08 00:00:00'));
$this->Controller->Auth->staticExpects($this->at(3))->method('user')->with('modified')->will($this->returnValue('2013-05-08 00:00:00'));
$this->Controller->Auth->staticExpects($this->at(4))->method('user')->will($this->returnValue(array(
'id' => 1,
'username' => 'admin',
'created' => '2013-05-08 00:00:00',
'modified' => '2013-05-08 00:00:00'
)));
$this->testAction('/posts/edit/1', array('method' => 'get'));
}
}
Run Code Online (Sandbox Code Playgroud)
测试输出
Username: admin
Created: 2013-05-08 00:00:00
Modified: 2013-05-08 00:00:00
All:
Array
(
[id] => 1
[username] => admin
[created] => 2013-05-08 00:00:00
[modified] => 2013-05-08 00:00:00
)
Modified:
Run Code Online (Sandbox Code Playgroud)
这里实际上有三个问题:
echo 'Email: ' . $this->Auth->user('email') . '<br>';之间添加一行(例如)echo,测试将失败并显示以下错误:Expectation failed for method name is equal to <string:user> when invoked at sequence index 2.这是有道理的,因为$this->at(1)它不再是真的.如何以(1)不重复的方式模拟Auth组件,(2)使测试输出与浏览器相同的东西,(3)允许我$this->Auth->user('foo')在不破坏测试的情况下在任何地方添加代码?
在回答这个问题之前,我不得不承认我没有使用CakePHP框架的经验.但是,我有很多使用PHPUnit和Symfony框架的经验,并遇到过类似的问题.为了解决你的观点:
请参阅我对第3点的回答
这样做的原因是您需要一个额外的...->staticExpects($this->at(5))...声明来涵盖对Auth-> user()的第6次调用.这些语句没有定义使用指定值对Auth-> user()的任何调用返回的值.它们定义了例如对Auth对象的第二次调用必须是带有参数'username'的方法user(),在这种情况下将返回'admin'.但是,如果您在下一点遵循该方法,这应该不再是一个问题.
我假设你在这里尝试实现的是独立于Auth组件测试你的控制器(因为坦白说测试控制器对用户对象进行一系列的getter调用是没有意义的).在这种情况下,模拟对象被设置为存根以始终返回特定的结果集,而不是期望具有特定参数的特定系列调用(请参阅存根上的PHP手册条目).这可以通过代码中的'$ this-> any()'替换'(x)'处的'$ this->来实现.然而,虽然这会否定我需要添加第2点中提到的额外线,但你仍然需要重复.遵循在代码之前编写测试的TDD方法,我建议如下:
public function testEdit() {
$this->Controller = $this->generate('Posts', array(
'components' => array(
'Auth' => array('user')
)
));
$this->Controller->Auth
->staticExpects($this->any())
->method('user')
->will($this->returnValue(array(
'id' => 1,
'username' => 'admin',
'created' => '2013-05-08 00:00:00',
'modified' => '2013-05-08 00:00:00',
'email' => 'me@me.com',
)));
$this->testAction('/posts/edit/1', array('method' => 'get'));
}
Run Code Online (Sandbox Code Playgroud)这将允许您的控制器更新,以便根据您的喜好以任何顺序获取用户属性,前提是模拟对象已经返回这些属性.无论控制器是否以及多久检索一次,都可以编写模拟对象以返回所有用户属性(或者可能都与此控制器相关).(请注意,在您的具体示例中,如果您的模拟包含'email',控制器中的pr()语句将从测试中输出与浏览器不同的结果,但我认为您不希望能够将新属性添加到记录中无需更新测试).
以这种方式编写测试意味着您的控制器编辑功能需要是这样的 - 一个更可测试的版本:
$this->autoRender = false;
if (!$this->Post->exists($id)) {
throw new NotFoundException(__('Invalid post'));
}
$user = $this->Auth->user();
if ($this->Post->find('first', array(
'conditions' => array(
'Post.id' => $id,
'Post.user_id' => Hash::get($user, 'id')
)
))) {
echo 'Username: ' . Hash::get($user, 'username') . '<br>';
echo 'Created: ' . Hash::get($user, 'created') . '<br>';
echo 'Modified: ' . Hash::get($user, 'modified') . '<br>';
echo 'All:';
pr($user);
echo 'Modified: ' . Hash::get($user, 'modified') . '<br>';
} else {
echo 'Unauthorized.';
}
Run Code Online (Sandbox Code Playgroud)
据我所知,Hash :: get($ record,$ key)是从记录中检索属性的正确CakePHP方法,尽管你在这里有简单的属性,我认为用户[$ key]也能正常工作.