4

我正在使用 Flexmock 模拟框架使用 Rspec2 编写测试。我希望我的一种方法可以缓存结果,并希望用我的模拟来验证这一点。

describe SomeClass do
  before do
    @mock = flexmock()
  end

  after do
    @mock.flexmock_verify()
  end

  it "method caches results"
    c = SomeClass.new(@mock)
    c.method
    @mock.should_receive(:expensive_method).never
    c.method.should == ['A']
  end
end

如果我想确保:expensive_method永远不会调用它,这很有效。但是,我希望我的班级能够在:method不调用传入(模拟)班级的任何内容的情况下做。有没有办法表达这个?

背景:在我的例子中,注入的类执行昂贵的操作,因此应该为相等的查询缓存结果。

更新
感谢到目前为止的建议,也许我只是在假设错误的事情,或者我想要的甚至没有意义。我实现缓存的方式是保存一个类变量SomeClass并将其添加到:method

def SomeClass
  @@cache_map = {}

  def method
    # extract key
    return @@cache_map[key] if @@cache_map.has_key?(key)
    # call :expensive_method to get result
    @@cache_map[key] = result
    return result
  end
end

现在,为了测试正确的缓存,我必须:extensive_method至少调用一次来加载缓存。我喜欢 David Chelimsky 的解决方案,但它并没有回答我的初衷,即:测试在第一次调用SomeClass.method注入的类之后不再调用(也:expensive_method没有其他任何东西)。

4

2 回答 2

9

指定缓存的常规方法是在调用之前先说@mock.should_receive(:expensive_method).oncemethod然后调用两次调用它的方法。

我还喜欢使用两个示例:一个指定它如何使用数据,一个指定它只检索一次数据:

describe Client do
  let(:service) { flexmock() }
  let(:client)  { Client.new(service) }

  it "uses data retrieved from service" do
    service.stub(:expensive_method).and_return('some data')
    client.method.should eq('some data')
  end

  it "only retrieves the data once" do
    service.should_receive(:expensive_method).once
    client.method
    client.method
  end
end

此外,您不需要调用flexmock_verify,因为这会自动发生。

于 2011-06-16T12:28:24.860 回答
1

当然不对模拟对象设置任何期望会实现这一点。对模拟的任何调用都会导致意外的调用失败(我承认我从未使用过 Flexmock,但我使用过的所有其他模拟框架都以这种方式工作)。

不幸的是,实际上没有任何方法可以在测试中明确说明这一点。也许更改测试名称以表明它,也许像“方法使用缓存结果而不调用模拟对象”。

于 2011-06-16T09:32:23.780 回答