On Wednesday, January 14, 2015 at 7:23:55 AM UTC-8, croceldon wrote:
>
> 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?
>
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
<https://relishapp.com/rspec/rspec-mocks/v/3-1/docs/verifying-doubles/dynamic-classes>.
There's an in-progress PR
<https://github.com/rspec/rspec-rails/pull/1238> 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
--
You received this message because you are subscribed to the Google Groups
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/rspec/c1f22264-313f-4e0d-ab6b-729767705a98%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.