1

假设您有一个简单的类,例如:

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 的这篇文章,它建议不要测试简单的访问器。

4

3 回答 3

2

这是非常简单的情况,正如您所说,您可能不应该那样访问访问者。但是如果情况有点复杂,或者访问器不是真正的访问器,但它内部有一些逻辑并且你真的很想测试它,那么你可以使用Objectinstance_variable_getand 。instance_variable_set

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

但是,我想这不是很好的测试技术,因为您正在干扰对象的内部状态,因此每当内部实现发生更改时,即使该类的公共接口没有更改,您也必须确保测试已更改。

于 2012-08-16T22:13:20.160 回答
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
于 2012-08-16T14:05:33.477 回答
0

也许是声音测试?如果是这样,而且是我在听,我会听到类似的话:“伙计,停止测试方法。重要的是行为。” . 我会回应以下内容:

describe Box do
  it "contains widgets" do
    widget = stub('widget')
    box    = Box.new

    box.add_widget(widget)
    box.widgets.should == [widget]
  end

  it "has no widgets by default" do
    Box.new.widgets.should == []
  end
end

由于#widgets 是访问框小部件的唯一(公共)方法,而#add_widget 是添加它们的唯一方法,因此没有其他方法可以测试Box行为,只能同时使用它们。

于 2012-08-17T08:36:36.637 回答