如何为改变实体状态的服务编写规范?

时间:2016-06-19 11:20:56

标签: php unit-testing bdd phpspec

我有一项服务MoneyMover,用于更改两个实体的状态:从amount减少sender金额并将此金额添加到receiver

我还没有实施。根据BDD,我正在为此功能编写规范:

function it_should_reduce_balance_of_sender(User $sender, User $receiver)
{
    $sender->getBalance()->willReturn(5);
    $this->moveFromSenderToReciever($sender, $receiver, 5);
    $sender->getBalance()->shouldReturn(0);
}

但是我只能测试我的服务状态而不是任何使用过的预言对象。所以这个规范会引发一个致命的错误:

  

调用未定义的方法Prophecy \ Prophecy \ MethodProphecy :: shouldReturn()

如何测试实体的状态变化?

我知道我可以使用类似的东西:

$sender->getBalance()->shouldBeCalled()->willReturn(5);
$sender->setBalance(0)->shouldBeCalled();

$this->moveFromSenderToReceiver($sender, $reciever, 5);

但是,如果我只是想测试该状态是否已经改变了呢?

2 个答案:

答案 0 :(得分:0)

你对这种方式进行验证的厌恶似乎并不合理。但是,不是试图将phpspec弯曲到你的意愿,也许更简洁的方法来解决这个问题是为了避免使用setter&完全是吸气鬼。这样的事情怎么样?

$sender->decreaseBalanceBy(5)->shouldBeCalled();

$this->moveFromSenderToReceiver($sender, $reciever, 5);

这种方式更自然地阅读,您不必担心从外部管理用户余额状态。

答案 1 :(得分:0)

你没关系

$sender->getBalance()->shouldBeCalled()->willReturn(5);
$sender->setBalance(0)->shouldBeCalled();

$this->moveFromSenderToReceiver($sender, $reciever, 5);

正确的做法是$sender$receiver是两个合作者。

你需要停下来思考一下:我的班级做什么?如果您的回答是更改特定用户的余额,那么我担心这不是正确答案(*)。
一个更好的方法可能是:你班级的行为是发送信息&#34;或者&#34;传递责任&#34;用户说他需要设置差额余额。你在这里说得非常安全,好吧,如果我在课堂上调用这个方法,setBalancegetBalance应该被调用(因为那是你班级应该做的!)。< / p>

如果要检查是否正确设置(或返回)了一个余额值,您必须创建另一个spec类(将指定您的User类)并执行所有将使您处于自信状态的测试用你的代码。

这样,如果两个测试都是绿色,那么你可以放心地依赖你所写的内容。

请记住,PHPSpec是一个BDD工具,而不是TDD工具,因此您必须将注意力集中在这些事情上:&#34;我班级的行为是什么?&#34;是问题。

为了完整起见,请考虑您不拥有的外部代码,例如ORM或DBAL或用于对数据库执行I / O操作的任何内容。假设您正在测试 描述的类需要将值写入数据库:您永远不会检查是否写入了实际数据。相反,你要做的是检查是否调用了方法调用(例如writeread或者他们得到的任何名称):如果是,你可以使用它,希望你的库有自己的测试套件,可以检查他们自己的代码和数据库之间的交互。

(*)由于您没有直接致电$user->amount = 0,所以答案不正确。首先,谦虚的amount,希望是User班的私人成员。因此,您只需将责任转交给其他人(User类,逻辑应归属于此类)。当然,在更高的抽象层次上,说你的班级改变了特定用户的平衡是可以的,在这里我需要这种分离只是为了将读者的注意力集中在一个可能真正的不同观点上,真的有助于理解为什么PHPSpec对这种操作有如此限制,如果你与其他工具比较,如PHPUnit或其他任何工具。