Skip to content

Correctly unstubs methods stubbed with `#any_instance`

gitlab-qa-bot requested to merge github/fork/alindeman/fixes_167 into master

Created by: alindeman

  • Instances stubbed with #any_instance would not be usable after the test finished because MethodDouble would stash the implementation of the method already overridden by AnyInstance::Recorder. When the test finished, that implementation would be restored on the object's singleton class, and any future calls to it would blow up with a stack overflow.
  • This fix only stashes methods if they are defined on the object's singleton class to begin with; AnyInstance::Recorder defines a method on the object's class so that method will not be stashed.
  • If there is no method on the object's singleton class, RSpec can safely define one there without stashing the original implementation. At the end of the test, the method is simply removed entirely from the singleton class. Any original implementation defined in the object's ancestor chain will show through again.
  • This issue cannot be fixed on MRI 1.8.6 because it does not support Method#owner. However, #any_instance itself is not supported on 1.8.6 for the same reason. The fix should not negatively affect 1.8.6, though, because the fallback behavior is to stash the method in all cases (which was the original behavior).
  • This commit also refactors the stashing behavior out into its own object. While not explicitly necessary, it helped me reason about the fix much easier than when all the responsibility was in MethodDouble (which also has other responsibilities).
  • Fixes #167 (closed)

Merge request reports