1

さて、パッケージの 1 つを PHPSpec テストに移行しようとしていますが、すぐにこの問題に遭遇しました。パッケージは shoppingcart パッケージなので、カートに 2 つのアイテムを追加すると、カートのカウントが 2 になることを簡単にテストしたいと思います。しかしもちろん、ショッピングカートに同じアイテムを 2 つ追加すると、カートに新しいエントリはありませんが、元のアイテムの「数量」は 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の制限ですか?

4

3 に答える 3

4

それで、あなたは夕食をとるためにレストランに歩いています。食事の選択肢が与えられ、その中から実際に今日食べたいものを選択し、夜の終わりに料金が請求されることを期待しています。あなたが期待していないのは、隣の素敵なカップルがシャトー・マルゴー95のボトルを次々と注文したことに対しても、レストランがあなたに請求することです。そのレストランとあなたの銀行に電話してください。

問題は、なぜ PhpSpec が今は気にしないメソッドをスタブ化することを強制するのかということではありません。問題は、今は気にしないメソッドをなぜ呼び出すのかということです。それらがあなたの期待の一部ではない場合、 PhpSpecはあなたの銀行に電話をかけるだけです。

于 2014-12-10T21:39:23.860 に答える
3

ええ、それをphpspecの「制限」と呼ぶことができます。基本的に phpspec は厳密な TDD であり、オブジェクト通信設計ツール IMO です。

コレクションに $cartItem を追加すると、予想以上のことが行われることがわかります。

最初のものは、スタブを使用する必要はありません (内部オブジェクト通信を気にしない場合) 例:

function it_adds_multiple_instances_of_a_cart_item()
{
    $this->add(new CartItem($id = 1, $options = ['size' => 1]));
    $this->add(new CartItem($id = 2, $options = ['size' => 2]));

    $this->shouldHaveCount(2);
}

function it_adds_two_same_items_with_different_sizes()
{
    $this->add(new CartItem($id = 1, $options = ['size' => 1]));
    $this->add(new CartItem($id = 1, $options = ['size' => 2]));

    $this->shouldHaveCount(2);   
}

function it_does_not_add_same_items()
{
    $this->add(new CartItem($id = 1, $options = []));
    $this->add(new CartItem($id = 1, $options = []));

    $this->shouldHaveCount(1);   
}

他の方法でもできます。コミュニケーションの観点から、オブジェクトの同じインスタンスを何度も照会することはあまり効果的ではありません。多くのパブリック メソッドは、さまざまな組み合わせを意味します。コミュニケーションを計画して、次のようなことを行うことができます。

function it_adds_multiple_instances_of_a_cart_item(CartItem $cartItem1, CartItem $cartItem2)
{
   $this->add($cartItem1);
   $cartItem1->isSameAs($cartItem2)->willReturn(false);
   $this->add($cartItem2);

   $this->shouldHaveCount(2);
}

function it_does_not_add_same_items((CartItem $cartItem1, CartItem $cartItem2)
{
    $this->add($cartItem1);
    $cartItem1->isSameAs($cartItem2)->willReturn(true);
    $this->add($cartItem2);

    $this->shouldHaveCount(1);   
}
于 2014-12-07T21:18:07.610 に答える