I am writing tests with Rspec2 using the Flexmock mocking framework. I expect one of my methods to cache results and want to verify this with my mock.
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
This works reasonable well if I want to make sure that :expensive_method
is never called. However, I am expecting my class to be able to do :method
without calling anything on the passed in (mock) class. Is there a way to express this?
Background: In my case, the injected class performs expensive operations and therefore results should be cached for equal queries.
Update
Thanks for the suggestions so far, maybe I'm just assuming wrong things or maybe what I want doesn't even make sense. The way I implemented my caching is by holding a class variable in SomeClass
and add to that in the :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
Now, in order to test the correct caching, I have to call :extensive_method
at least once to load the cache. I like David Chelimsky's solution, but it isn't answering my original intent, which is: Test that after the first call to SomeClass.method
the injected class is never called again (neither :expensive_method
nor anything else).
The conventional way to specify caching is to say @mock.should_receive(:expensive_method).once
before invoking method
at all, and then invoke the method that calls it twice.
I also like to use two examples for this: one to specify how it uses the data, one to specify that it only retrieves the data once:
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
Also, you don't need to call flexmock_verify
, as that happens automatically.
Surely not setting any expectations on the mocked object will achieve this. Any call made to the mock will result in an unexpected call failure (I'll admit I've never used Flexmock but every other mocking frame work I've used works this way).
Unfortunately there isn't really any way to make this explicit in the test. Maybe change the test name to indicate it, maybe something like "method uses cached result without calling mocked object".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With