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

最後の2つのテストがどのように同一になるかに注意してください。私はこれらの重複するケースを回避する方法に苦労しています。最初の2つのケースでは暗黙的に#widgetsをテストしていますが、明示的なテストも必要だと感じています。ただし、このためのコードは2番目のケースと同じになります。

クラスに3つのパブリックメソッドがある場合、それらの各メソッドに対応する少なくとも1つのテストが必要です。私が間違っている?

アップデート

単純なアクセサーをテストしないようにアドバイスするRonJeffriesによるこの記事を見つけました。

4

3 に答える 3

2

これは非常に単純なケースであり、あなたが言ったように、おそらくそのようなアクセサーはすべきではありません。ただし、ケースがもう少し複雑な場合、またはアクセサーが実際にはアクセサーではないが、内部にいくつかのロジックがあり、本当にテストしたい場合は、 Objectinstance_variable_getのandinstance_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

少なくともこの場合、コードの重複を回避できるかどうかはわかりません。ウィジェットの配列を取るコンストラクターがない場合は、いずれかの方法で一方のメソッドを使用して他方をテストする必要があります。この場合、テストを変更できる 1 つの方法は次のとおりです。

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 に答える