2

RSpecでテストしたい簡単な方法があります。apply確実に1つずつ減らしていきたいですplayer.capacity。これを行うために、プレーヤーオブジェクトをモックし、正しいメッセージを受信するかどうかをテストしています。

コード

class DecreaseCapacity < Item
  def apply player
    player.capacity -= 1
  end
end

テスト

describe DecreaseCapacity, "#apply" do
  it "should decrease capacity by one" do
    player = double()
    player.should_receive(:capacity)   # reads the capacity
    player.should_receive(:capacity=)  # decrement by one
    subject.apply player
  end
end

失敗メッセージ

1) DecreaseCapacity#apply should decrease the player's capacity by one
   Failure/Error: subject.apply player
   undefined method `-' for nil:NilClass
   # ./item.rb:39:in `apply'
   # ./item_spec.rb:25

何が起きてる?なぜplayer.capacity -= 1呼びかけようとし-ているのnilですか?

4

1 に答える 1

10

問題は、プレーヤーをスタブした方法で、capacityが呼び出されたときにnilを返すことです。次のように変更する必要があります。

player.should_receive(:capacity).and_return(0)
player.should_receive(:capacity=).with(1)

その理由を理解するために、コードで何が起こっているのかを分析してみましょう。次のように展開すると、問題がわかりやすくなります-=

player.capacity = player.capacity - 1

スタブプレーヤーを使用すると、次のようになります。

player.capacity = nil - 1

これはまさにRSpecが不満を言っていることです。

それでは、テストを作成するためのより良い方法を提案させてください。テストは単に実装を反映したものであり、メソッドをテストするものではありません。つまり、applyメソッドがプレーヤーの容量を1つ増やすことをテストするのではなく、apply呼び出しcapacityてからをテストしますcapacity=。同じことだと思うかもしれませんが、それはメソッドをどのように実装したかを知っているからです。

これは私がテストを書いた方法です:

it "increments a player's capacity" do
  player = Player.new # notice that I use a real Player
  player.capacity = 0
  subject.apply(player)
  player.capacity.should == 1
end

Playerスタブを設定する代わりに実際のオブジェクトを使用しました。これは、の実装Player#capacityが単なるアクセサーであると想定しているため、テストに干渉するロジックがそこにないためです。スタブを使用する場合のリスクは、スタブが実際のオブジェクトよりもさらに複雑になる場合があることです(この場合、私が主張します)。つまり、テストが実際のコードよりも間違っている可能性が高くなります。

RSpecの表現力を最大限に活用したい場合は、次のようにテストを作成することもできます。

it "increments a player's capacity" do
  player = Player.new
  player.capacity = 0
  expect { subject.apply(player) }.to change { player.capacity }.to(1)
end
于 2010-12-22T06:58:34.563 に答える