问题
I have a spec like
describe MyClass do
it_behaves_like SharedClass, MyClass.new
end
and in my shared example spec, I have
shared_examples_for SharedClass do |instance|
before do
instance.some_my_class_method = double
end
# some specs here
end
There are few methods in MyClass instance that I cannot stub in the shared_examples_for block, so I want to stub them before passing it in it_behaves_like statement. like,
describe MyClass do
before do
@instance = MyClass.new
@instance.stub(:my_class_method)
end
it_behaves_like SharedClass, @instance
end
but I cannot do that.It throws me
NoMethodError:
undefined method `some_my_class_method=' for nil:NilClass
somehow I am not able to access that @instance object in the shared_examples_for context. I am using ruby 1.9.3p392 and rspec (2.14.1)
回答1:
The problem is that the arguments you pass to it_behaves_like
are evaluated at the time it_behaves_like
is called, while the before
block is evaluated just before the shared example is executed, which occurs at a later time. As a result, @instance
as an argument is evaluated to nil
and the formal parameter instance
is assigned nil
, resulting in your undefined method
error.
I don't know of any easy way to do what you're trying to accomplish. One alternative shown in this documentation is to eliminate the formal parameter and require the caller to pass a block which uses let
to establish the argument value, using some agreed to variable, as follows:
describe MyClass do
it_behaves_like SharedClass {let(:instance) { MyClass.new }}
end
describe MyClass do
it_behaves_like SharedClass do
let(:instance) do
myClass = MyClass.new
myClass.stub(:my_class_method)
myClass
end
end
end
In addition to being more verbose, however, this has the disadvantage that there is no implicit documentation within your shared example that it expects instance
to set when it's called.
Although I've not seen it discussed anywhere, a somewhat hacky alternative would be have your shared example use the agreed-to-variable from the block if and only if the value of the formal parameter is nil
, which could be defaulted for convenience. Unfortunately, you can't use the same variable for both, as the value of the parameter will always take precedence.
来源:https://stackoverflow.com/questions/20899204/how-to-pass-objects-with-stubbed-methods-in-it-behaves-like-to-shared-examples-f