对此有几点想法。
您的用户模型正在与合作者合作以实现其自己的行为 - 该合作者是 hash_hmac 函数。PHPSpec 的黄金法则是 Subject Under Specification,一次处理一个类,稍后再考虑协作者的实现细节。我发现这有助于我在设计课程时考虑到关注点分离原则,而且我经常发现自己在问这个问题——这个课程真正关心的是什么?
例如,您UserModel
不应该真正关心您的系统使用哪种哈希算法来保护密码。然而,它可以知道一个对象,称为它HashingProvider
,它能够散列密码,甚至只接收一个或多个字符串并返回某种散列表示。
通过以这种方式重新构建您的架构UserModel
,您将能够充分利用 PHPSpec 中的 Mocking(这里很棒)来专注于实现您的UserModel
第一个,然后继续HashingProvider
您的规范可能如下所示:
<?php
namespace spec;
use PHPSpec2\ObjectBehavior;
class User extends ObjectBehavior
{
function it_should_be_initializable()
{
$this->shouldHaveType('User');
}
/**
* @param /Some/HashingProvider $hashProvider
*/
function it_should_authenticate_if_proper_signature_given($hashProvider)
{
$this->setEmail('email');
$this->setPassword('password');
$hashProvider->hash('email', 'password')->willReturn('signature');
$this->authenticate('signature', $hashProvider)->shouldReturn(true);
}
/**
* @param /Some/HashingProvider $hashProvider
*/
function it_should_not_authenticate_if_invalid_signature_given($hashProvider)
{
$this->setEmail('email');
$this->setPassword('password');
$hashProvider->hash('email', 'password')->willReturn('signature');
$this->authenticate('bad_signature', $hashProvider)->shouldReturn(false);
}
}
然后,您的用户模型可以按照您的规范描述的方式使用该协作者:
<?php
class User extends Model
{
public function authenticate($signature, $hashProvider)
{
$hash = $hashProvier->hash($this->email, $this->password);
if ($hash == $signature)
$this->_authenticated = true;
return $this->_authenticated;
}
}