J.P*_*.P. 2 ruby unit-testing rspec rspec2
我有一个简单的方法,我想用RSpec测试.我想确保apply减少player.capacity一个.为此,我已经模拟了一个玩家对象并正在测试它是否收到正确的消息.
class DecreaseCapacity < Item
def apply player
player.capacity -= 1
end
end
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?为什么player.capacity -= 1试图调用-上nil?
The*_*heo 10
问题是,当你capacity调用播放器的方式时,它会在调用时返回nil .你需要这样改变:
player.should_receive(:capacity).and_return(0)
player.should_receive(:capacity=).with(1)
Run Code Online (Sandbox Code Playgroud)
要理解原因,让我们分解代码中发生的事情.如果我们扩展-=为:将更容易看到问题:
player.capacity = player.capacity - 1
Run Code Online (Sandbox Code Playgroud)
使用存根播放器,它变为:
player.capacity = nil - 1
Run Code Online (Sandbox Code Playgroud)
这正是RSpec所抱怨的.
现在,让我建议一个更好的方法来编写测试.您的测试只是镜像您的实现,它不测试方法.我的意思是它没有测试该apply方法将玩家的容量增加一个 - 它测试该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
Run Code Online (Sandbox Code Playgroud)
我使用了一个真实的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
Run Code Online (Sandbox Code Playgroud)