在测试mutator和accessor方法时避免重复

时间:2012-08-16 13:59:03

标签: ruby unit-testing rspec tdd

假设您有一个简单的类:

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

2 个答案:

答案 0 :(得分:2)

这是一个非常简单的案例,正如你所说,你可能不应该这样的访问者。但是如果案例有点复杂,或者访问者不是真正的访问者,但它内部有一些逻辑而你真的想测试它,那么你可以使用instance_variable_getinstance_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