开发者

Testing memoization

I have an expensive method called calculate_total. I need a method called total that will return the result of calculate_total. Subsequent calls to total should return the previous result of calculate_total.

I want to do this in a test driven way. Here are my tests (I'm using RSpec):

describe Item do
  describe "total" do
    before do
      @item = Item.new
      @item.stub!(:calculate_total => 123)
    end

    it "returns the calculated total" do
      @item.total.should == 123
    end

    it "subsequent calls return the original result" do
      previous_total = @item.total
      @item.total.should equal(previous_total)
    end
  end
end

This is not开发者_开发百科 a good test because the following method makes the tests pass, but I was expecting the second test to fail:

def total
  calculate_total
end

The reason is calculate_total returns a Fixnum so ruby doesn't see the result as 2 different objects. I was expecting the second test to fail, so then I could do the following to make it pass:

def total
  @total ||= calculate_total
end

Anyone know a better way to test this?

I don't think this is the best/correct way to test it, but I've settled on this: https://gist.github.com/1207270


I think your gist is fine: what you want to test is whether or not calculate_total is called more than once, and that's exactly what you're doing. The only difference I might suggest is a slightly more explicit test:

it "subsequent calls don't calculate the total, but still return the original result" do
  @item.should_receive(:calculate_total).once
  2.times do 
    @item.total.should == 123
  end
end


You could call it twice in the same spec and compare the returned objects to make sure they are equal:

it "should memoize it" do
  total = Item.total
  # second call will yield a different object if not memoized
  Item.total.should == total
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜