Myron Marston
2010-Feb-08 17:44 UTC
[rspec-users] [rspec-rails] For helper specs, why is the helper cached in the class between running each example?
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: def something_expensive @something_expensive ||= do_something_expensive end 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[1] code in rspec-rails'' ExampleHelperGroup: 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). Thanks, Myron [1] http://github.com/dchelimsky/rspec-rails/blob/1.3.2/lib/spec/rails/example/helper_example_group.rb#L89-91
David Chelimsky
2010-Feb-09 01:17 UTC
[rspec-users] [rspec-rails] For helper specs, why is the helper cached in the class between running each example?
On Mon, Feb 8, 2010 at 1:44 PM, Myron Marston <myron.marston at gmail.com> wrote:> 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: > > ?def something_expensive > ? ?@something_expensive ||= do_something_expensive > ?end > > 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[1] code in > rspec-rails'' ExampleHelperGroup: > > ? ? ? ?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).Someone just submitted a ticket w/ a patch on this last week: https://rspec.lighthouseapp.com/projects/5645-rspec/tickets/627 It''ll be released with rspec-rails-1.3.3, some time in the next few days. Cheers, David> > Thanks, > Myron > > [1] http://github.com/dchelimsky/rspec-rails/blob/1.3.2/lib/spec/rails/example/helper_example_group.rb#L89-91 > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Myron Marston
2010-Feb-09 01:31 UTC
[rspec-users] [rspec-rails] For helper specs, why is the helper cached in the class between running each example?
Thanks, David. I searched the google group for discussions of my problem but forgot to search the github issues. I''ll be sure to check there next time! On Feb 8, 5:17?pm, David Chelimsky <dchelim... at gmail.com> wrote:> On Mon, Feb 8, 2010 at 1:44 PM, Myron Marston <myron.mars... at gmail.com> wrote: > > 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: > > > ?def something_expensive > > ? ?@something_expensive ||= do_something_expensive > > ?end > > > 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[1] code in > > rspec-rails'' ExampleHelperGroup: > > > ? ? ? ?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). > > Someone just submitted a ticket w/ a patch on this last week: > > https://rspec.lighthouseapp.com/projects/5645-rspec/tickets/627 > > It''ll be released with rspec-rails-1.3.3, some time in the next few days. > > Cheers, > David > > > > > Thanks, > > Myron > > > [1]http://github.com/dchelimsky/rspec-rails/blob/1.3.2/lib/spec/rails/ex... > > _______________________________________________ > > rspec-users mailing list > > rspec-us... at rubyforge.org > >http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
David Chelimsky
2010-Feb-09 01:33 UTC
[rspec-users] [rspec-rails] For helper specs, why is the helper cached in the class between running each example?
On Mon, Feb 8, 2010 at 9:31 PM, Myron Marston <myron.marston at gmail.com> wrote:> Thanks, David. ?I searched the google group for discussions of my > problem but forgot to search the github issues. ?I''ll be sure to check > there next time!No worries - I was just surprised that this has been a theoretical problem for so long and three people bring it up within a week of each other! Glad we got it visible and fixed. Cheers, David> > On Feb 8, 5:17?pm, David Chelimsky <dchelim... at gmail.com> wrote: >> On Mon, Feb 8, 2010 at 1:44 PM, Myron Marston <myron.mars... at gmail.com> wrote: >> > 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: >> >> > ?def something_expensive >> > ? ?@something_expensive ||= do_something_expensive >> > ?end >> >> > 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[1] code in >> > rspec-rails'' ExampleHelperGroup: >> >> > ? ? ? ?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). >> >> Someone just submitted a ticket w/ a patch on this last week: >> >> https://rspec.lighthouseapp.com/projects/5645-rspec/tickets/627 >> >> It''ll be released with rspec-rails-1.3.3, some time in the next few days. >> >> Cheers, >> David >> >> >> >> > Thanks, >> > Myron >> >> > [1]http://github.com/dchelimsky/rspec-rails/blob/1.3.2/lib/spec/rails/ex... >> > _______________________________________________ >> > rspec-users mailing list >> > rspec-us... at rubyforge.org >> >http://rubyforge.org/mailman/listinfo/rspec-users >> >> _______________________________________________ >> rspec-users mailing list >> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >