开发者

How to make a class object instance to return a predefined value?

I am using Ruby on Rails 3.1.0 and the rspec-rails 2 gem. I am testing my controller code (BTW: I am newbie to rspec) and I would like to make possible that a class object instance returns a predefined value. That is, in my controller I have:

def create
  ...

  if @current_user.has_authorization?
    ...
  else
    ...
  end
end

In order to test the "else part" of the if statement I would like to make possible that (for the current spec example that I am working on - read below for a sample implementation) the @current_开发者_JS百科user.has_authorization? returns false.

How can I make that?


I tried the following in my spec file, but it seems do not work as expected:

it "should have no authorization" do
  @current_user.stub(:has_authorization?).and_return(false)

  # I also tried the following and it still doesn't work
  # @current_user.should_receive(:has_authorization?).and_return(false)

  post :create
  ...
end


@current_user in the context of your rspec test is not the same as @current_user in the context of your controller. One is an instance variable, in the instance of your controller class that Rails is running. The other is an instance variable in your rspec test.

You aren't supposed to poke at your user variable, but rather need to make it so Rails finds a User supplied by the test framework. Take a look at this example.


To avoid that issue you could use mocha, to do that do the following:

Add the mocha gem to your Gemfile and run bundle install.

Then change the Rspec mock configuration framework in your spec_helper.rb file

RSpec.configure do |config|
  config.mock_with :mocha
  # config.mock_with :rspec
end

Then in your spec you can do this

it "should have no authorization" do
  User.any_instance.stubs(:has_authorization?).returns(false)
  post :create
  ...
end

This (or the correct answer from Coderer) will solve your issue.

Notice that as far as I know there is no any_instance equivalent in Rspec mocking functions.


When your spec is running, self is pointing to a test object (try p self or puts self.class inside a spec sometime and see for yourself), so @current_user is referring to an instance variable on that test object. It has nothing whatsoever to do with the @current_user instance variable on your controller.

One way to do what you want is to create a current_user method or accessor on your controller, and call it instead of accessing @current_user directly. Then you can stub or mock that method from your spec, assuming you can get a pointer to your controller instance.

Another way is to set the @current_user variable directly from inside your spec. Again, get a pointer to your controller instance, then do x = mock("user"); controller.instance_variable_set(:@current_user, x) then you can mock/stub methods on x.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜