RSpec 模拟失败并显示“未定义的方法”-“对于 nil:NilClass”
我有一个简单的方法,想用 RSpec 进行测试。我想确保 apply
使 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
上调用 -
?
I have a simple method that I want to test with RSpec. I want to ensure that apply
decrements player.capacity
by one. To do this, I have mocked a player object and am testing to see if it receives the correct messages.
Code
class DecreaseCapacity < Item
def apply player
player.capacity -= 1
end
end
Test
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
Failure Message
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
What's going on here? Why is player.capacity -= 1
attempting to call -
on nil
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是,当调用
capacity
时,您对播放器进行存根的方式将返回 nil。您需要像这样进行更改:要了解原因,让我们分解一下代码中发生的情况。如果我们将
-=
扩展为:对于你的存根播放器,它会变成这样:
这正是 RSpec 所抱怨的。
现在,让我建议一种更好的编写测试的方法。您的测试只是反映您的实现,它不会测试该方法。我的意思是,它不会测试
apply
方法是否将玩家的容量加一 - 它测试apply
调用capacity
然后是容量=
。您可能认为这是同一件事,但这只是因为您知道如何实现该方法。这就是我编写测试的方式:
我使用了真正的 Player 对象,而不是设置存根,因为我假设 Player#capacity 的实现只是一个访问器,那里没有逻辑可以干扰我的测试。使用存根的风险在于,有时存根变得比真实对象更复杂(我认为在这种情况下),这意味着您的测试更有可能比实际代码错误。
如果您想使用 RSpec 的完整表达能力,您也可以这样编写测试:
The problem is that the way you've stubbed the player it will return nil when
capacity
is called. You need to change like so:To understand why, let's break down what happens in your code. It will be easier to see the problem if we expand the
-=
to:With your stubbed player it becomes this:
which is exactly what RSpec complains about.
Now, let me suggest a better way to write the test. Your test simply mirrors your implementation, it does not test the method. What I mean by that is that it doesn't test that the
apply
method increments a player's capacity by one -- it tests thatapply
callscapacity
and thencapacity=
. You may think it's the same thing, but that's only because you know how you have implemented the method.This is how I would have written the test:
I used a real
Player
object instead of setting up a stub, because I assume that the implementation ofPlayer#capacity
is just an accessor, there's no logic in there to interfere with my test. The risk with using stubs is that sometimes the stubs get even more complicated than the real objects (as in this case, I would argue), and that means that it's more likely that your test is wrong than your actual code.You can also write the test like this, if you want to use the full expressiveness of RSpec: