I ran into a recent problem writing specs for a helper. I was testing
a helper that uses the standard memoization technique of caching the
result of an expensive calculation in an instance variable:
@something_expensive ||= do_something_expensive
I have several different rspec examples for this one helper method,
all of which mock out a method that do_something_expensive calls,
which should in turn cause a different return value from
#something_expensive. When I ran my specs, I wound up getting the
same return value for each spec–the return value from the first spec
that ran. After investigating it a bit, I ran across this code in
def helper self.class.helper end
The #helper method simply delegates to the class’s helper method,
which memoizes the helper object in an instance variable. The result
of this is that the helper is cached in the class between example
runs, and because of the memoization in my helper method, subsequent
specs were returning the same value.
I found a work around:
after(:each) do helper.instance_variable_set('@something_expensive', nil) end
But it feel like a bit of a hack, and it’s annoying/frustrating that I
have to do this. My specs shouldn’t have to be aware of the
memoization and manually clear it to work.
Why is the helper object cached in the class between running each
example? This can accidentally lead to spec interdependencies (i.e.
example B only passes if it runs after example A has run, because
example A puts the helper object into a certain state that example B
unknowingly depends on).