好的,所以我试图将我的一个软件包移到PHPSpec测试中,但是很快我遇到了这个问题。
这些包装是购物车包装,因此我想测试一下,当您将两个商品添加到购物车时,购物车的数量为两个,很简单。
但是,当然,在购物车中,当添加两个相同的商品时,购物车中不会有新条目,但是原始商品的“数量”为2。因此,例如,当它们不是时,不同的大小。
因此,每个项目都根据其ID和选项由唯一的rowId标识。
这是生成rowId的代码(由add()
方法使用):
protected function generateRowId(CartItem $item)
{
return md5($item->getId() . serialize($item->getOptions()));
}
现在,我已经像这样编写了测试:
public function it_can_add_multiple_instances_of_a_cart_item(CartItem $cartItem1, CartItem $cartItem2)
{
$this->add($cartItem1);
$this->add($cartItem2);
$this->shouldHaveCount(2);
}
但是问题是,两个存根都为
null
方法返回getId()
。因此,我尝试为该方法设置willReturn()
,因此我的测试变成了:public function it_can_add_multiple_instances_of_a_cart_item(CartItem $cartItem1, CartItem $cartItem2)
{
$cartItem1->getId()->willReturn(1);
$cartItem2->getId()->willReturn(2);
$this->add($cartItem1);
$this->add($cartItem2);
$this->shouldHaveCount(2);
}
但是现在我得到了错误,告诉我意外的方法称为
getName()
。因此,我必须对CartItem接口上的所有方法进行相同的调用:public function it_can_add_multiple_instances_of_a_cart_item(CartItem $cartItem1, CartItem $cartItem2)
{
$cartItem1->getId()->willReturn(1);
$cartItem1->getName()->willReturn(null);
$cartItem1->getPrice()->willReturn(null);
$cartItem1->getOptions()->willReturn([]);
$cartItem2->getId()->willReturn(2);
$cartItem2->getName()->willReturn(null);
$cartItem2->getPrice()->willReturn(null);
$cartItem2->getOptions()->willReturn([]);
$this->add($cartItem1);
$this->add($cartItem2);
$this->shouldHaveCount(2);
}
现在工作正常,测试为绿色。但这感觉不对...我是否缺少某些东西,或者这是对PHPSpec的限制吗?
最佳答案
现在工作正常,测试为绿色。但这感觉不对...我是否缺少某些东西,或者这是对PHPSpec的限制吗?
我认为在那种情况下感觉不错是件好事,因为应该这样做。就像上面提到的@ l3l0一样,PHPSpec是一个设计工具,在这里可以为您提供有关设计的清晰信息。
您遇到的困难是您的Cart
违反了单一责任原则-它做的不只是一件事-它管理CartItems
并知道如何从中生成RowId
。因为PHPSpec迫使您保留CartItem
的整个行为,所以它会向您提供一条消息,以重构生成RowId
的过程。
现在,假设您将RowIdGenerator提取为单独的类(此处未涵盖其自身的规范):
class RowIdGenerator
{
public function fromCartItem(CartItem $item)
{
return md5($item->getId() . serialize($item->getOptions()));
}
}
然后,您通过构造函数将此生成器作为对Cart的依赖项注入:
class Cart
{
private $rowIdGenerator;
public function __construct(RowIdGenerator $rowIdGenerator)
{
$this->rowIdGenerator = $rowIdGenerator;
}
}
然后,您的最终规格可能如下所示:
function let(RowIdGenerator $rowIdGenerator)
{
$this->beConstructedWith($rowIdGenerator);
}
public function it_can_add_multiple_instances_of_a_cart_item(RowIdGenerator $rowIdGenerator, CartItem $cartItem1, CartItem $cartItem2)
{
$rowIdGenerator->fromCartItem($cartItem1)->willReturn('abc');
$rowIdGenerator->fromCartItem($cartItem1)->willReturn('def');
$this->add($cartItem1);
$this->add($cartItem2);
$this->shouldHaveCount(2);
}
而且因为您嘲笑了id生成器的行为(并且您知道必须进行这种通信),所以您现在符合SRP。现在感觉好点了吗?