Intermittent failures of instance_double

19 views
Skip to first unread message

croceldon

unread,
Jan 14, 2015, 10:23:55 AM1/14/15
to rs...@googlegroups.com, jason...@camfil.com
I have the following in a controller spec:

let(:project) { instance_double('Project', metric?: false) }

But I get this error when running the spec:

Project does not implement: metric?

Project does most definitely implement metric?.  The weird thing is that I have this exact same instance double specified in a different model spec (including the "metric?: false" part), and it runs without any problems.

How can I resolve this?

Myron Marston

unread,
Jan 14, 2015, 11:19:11 AM1/14/15
to rs...@googlegroups.com, jason...@camfil.com
There are a couple possible reasons for this:
  •  Verifying doubles use "is the constant defined?" in order to decide whether or not to perform verification.  So if you had a file that defined a `Project::SomeNestedConstant` class, had another file that defined the actual `Project` class, and ran your spec with only the former file loaded, you'd get this.  The file that defines `Project::SomeNestedConstant` would cause the `Project` constant to be defined, but the class definition wouldn't be loaded, so RSpec would tell the method is not implemented.
  • Does `Project` define methods dynamically?  For example, is it an ActiveRecord model?  In the AR case, column methods are defined lazily on first use -- which means that if you have a `metric` column, `Project.method_defined(:metric?)` initially returns false, and then later, after `Project.new.metric?` has been called, `Project.method_defined?(:metric?)` will return true because AR has defined the method.  This is a known issue that we've documented.  There's an in-progress PR in rspec-rails to partially address the AR case.
If it's the latter, you have a few possibilities to deal with it:

  • Change from `instance_double('Project', metric?: false)` to `object_double(Project.new, metric?: false)`. Even though `Project.method_defined?(:metric?)` returns false initially (which is the way instance doubles do verification), `Project.new.respond_to?(:metric?)` should always return true (which is how object double is able to work, since it's given an instance rather than the class itself).
  • Call `Project.define_attribute_methods` before the first `instance_double('Project')`.  (This is essentially what the in-progress PR linked above will do).
  • Explicitly define a `metric?` method in your `Project` model. It can simply `super` to the ActiveRecord dynamically generated one.  This is the solution demonstrated in the docs I linked to above.
HTH,
Myron

croceldon

unread,
Jan 14, 2015, 11:42:13 AM1/14/15
to rs...@googlegroups.com, jason...@camfil.com
Ok, makes sense.  It is an AR model.

Thanks for the suggestions.
Reply all
Reply to author
Forward
0 new messages