假设您有一个简单的类:
class Box
def initialize
@widgets = []
end
def add_widget(widget)
@widgets << widget
end
def widgets
@widgets
end
end
我会写一个看起来像这样的测试:
describe Box do
describe "#initialize" do
it "creates an empty box"
Box.new.widgets.should == []
end
end
describe "#add_widget" do
it "adds a widget to the box"
widget = stub('widget')
box = Box.new
box.add_widget(widget)
box.widgets.should == [widget]
end
end
describe "#widgets" do
it "returns the list of widgets"
widget = stub('widget')
box = Box.new
box.add_widget(widget)
box.widgets.should == [widget]
end
end
end
注意最后两个测试最终是如何相同的。我正在努力避免这些重叠的案例。我在前两个案例中隐式测试#widgets但我觉得应该还有一个明确的测试。但是,此代码最终与第二种情况相同。
如果一个类有3个公共方法,那么我希望至少有一个测试对应于每个方法。我错了吗?
更新
我找到了Ron Jeffries的this article,建议不要测试简单的访问器。
答案 0 :(得分:2)
这是一个非常简单的案例,正如你所说,你可能不应该这样的访问者。但是如果案例有点复杂,或者访问者不是真正的访问者,但它内部有一些逻辑而你真的想测试它,那么你可以使用instance_variable_get
和instance_variable_set
Object
describe Box do
describe "#initialize" do
it "creates an empty box" do
Box.new.widgets.should == []
end
end
describe "#add_widget" do
it "adds a widget to the box" do
widget = stub('widget')
box = Box.new
box.add_widget(widget)
box.instance_variable_get(:@widgets).should == [widget]
end
end
describe "#widgets" do
it "returns the list of widgets" do
widget = stub('widget')
box = Box.new
box.instance_variable_set(:@widgets, [widget])
box.widgets.should == [widget]
end
end
end
但是,我认为这不是很好的测试技术,因为你干扰了对象的内部状态,因此每当内部实现发生变化时,你必须确保测试被更改,即使该类的公共接口没有改变。
答案 1 :(得分:0)
至少在这种情况下,我不确定您是否可以避免代码重复。如果您没有构造函数来获取小部件数组,则必须使用一种方法来测试另一种方法。在这种情况下,您可以改变测试的一种方法可能如下:
describe Box do
describe "#initialize" do
it "creates an empty box"
Box.new.widgets.should == []
end
end
describe "#add_widget" do
before do
@widget = stub('widget')
@box = Box.new
@box.add_widget(@widget)
end
it "adds a widget to the box, which gets returned by #widgets"
@box.widgets.should == [@widget]
end
end
end