I'm writing some tests for a web application and one of the controllers calls resolve
on a Scope
object, which returns a slightly modified scope. In the test I would like to stub this method to return the original scope (passed as a parameter to Scope.initialize
).
The Scope
object
class Scope
def initialize(scope)
@scope = scope
end
def resolve
# Return a modified scope.
end
end
The controller
class FooController < ApplicationController
def show
foos = Scope.new(Foo.some_foos).resolve
respond_with foos
end
end
The test
it "does something" do
allow_any_instance_of(Scope).to receive(:resolve).and_return(???.scope)
get :show
# Do some assertions.
end
What do I need to put where the ???
are in order to stub the resolve
method on any instance of Scope
to return the original scope that it was created with?
I'm using Rspec 3.4.2.
First you will want to create a attribute reader on Scope so that you can access @scope
without using instance_variable_get
:
class Scope
attr_reader :scope
def initialize(scope)
@scope = scope
end
def resolve
# Return a modified scope.
end
end
If you use block implementation the receiver is passed as the first arg:
allow_any_instance_of(Scope).to receive(:resolve) do |s|
s.scope
end
However using allow_any_instance_of
is strongly discouraged and usually a sign that your tests are poking around too much in how your controllers do their job instead of actually testing their behavior in a future proof way.
I would instead use a unit test which tests Scope
and request specs which tests the controller in conjunction with feature specs. This is how I test applications that use Pundit and is a robust strategy.