【问题标题】:Testing memoization测试记忆
【发布时间】:2011-11-14 02:01:48
【问题描述】:

我有一个名为calculate_total 的昂贵方法。我需要一个名为total 的方法,它将返回calculate_total 的结果。对total 的后续调用应返回calculate_total 的先前结果。

我想以测试驱动的方式执行此操作。这是我的测试(我正在使用 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

这不是一个好的测试,因为以下方法使测试通过,但我预计第二个测试会失败:

def total
  calculate_total
end

原因是 calculate_total 返回一个 Fixnum 所以 ruby​​ 不会将结果视为 2 个不同的对象。我期待第二次测试失败,所以我可以执行以下操作以使其通过:

def total
  @total ||= calculate_total
end

有人知道更好的测试方法吗?

我不认为这是测试它的最佳/正确方法,但我已经确定了这一点:https://gist.github.com/1207270

【问题讨论】:

  • 他们是否也有相同的____id_____?
  • 是的。所以,据我所见,我的测试无法区分 1+2+3 和 6
  • 嗯,也许它缓存了那些。我要你明确创建一个新的 Fixnum,还是围绕它创建一个包装器?可能不值得,除非作为练习,不确定。

标签: ruby unit-testing testing rspec


【解决方案1】:

我认为您的要点很好:您要测试的是 calculate_total 是否被多次调用,而这正是您正在做的。我可能建议的唯一区别是稍微更明确的测试:

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

【讨论】:

  • 现在我的问题是:如果 calculate_total 不是公共方法怎么办 :)(我通常不喜欢将消息期望放在私有方法上)
【解决方案2】:

您可以在同一规范中调用它两次并比较返回的对象以确保它们相等:

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

【讨论】:

    猜你喜欢
    • 2015-07-09
    • 2014-01-07
    • 1970-01-01
    • 2012-11-16
    • 2021-04-02
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多