I have a Rails 4 application, and here is my lib/foobar:
jan@rmbp ~/D/r/v/l/foobar> tree
.
├── foo_bar.rb
└── foobar_spec.rb
0 directories, 2 files
And the files:
foobar_spec.rb
require "spec_helper"
describe "FooBar" do
subject { FooBar.new }
its(:foo) { should == "foo"}
#stubbed version of test crashes
#FooBar.stub(:foo).and_return("bar")
#subject { FooBar.new }
#its(:foo) { should == "bar"}
end
foo_bar.rb
class FooBar
def foo
"foo"
end
end
spec_helper.rb:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# commented for zeus two runs bug
require 'rspec/autorun'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.include Features::SessionHelpers, type: :feature
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
end
The spec passes fine. But when I uncomment this line:
# FooBar.stub(:foo).and_return("bar")
It fails with:
/Users/jan/.rvm/gems/ruby-2.0.0-p247/gems/rspec-mocks-2.14.3/lib/rspec/mocks.rb:26:in `proxy_for': undefined method `proxy_for' for nil:NilClass (NoMethodError)
What is wrong?
EDIT:
Also, I can't seem to be able to use webmock
either.
stub_request(:post, "https://accounts.google.com/o/oauth2/token")
.with(:body => { "client_id" => CLIENT_ID,
"client_secret" => CLIENT_SECRET,
"refresh_token" => refresh_token, }
).to_return(:status => 200,
:body => File.read("#{$fixtures}/refresh_token.json"))
Returns:
/Users/jan/Documents/ruby/vince.re/lib/youtube/you_tube_test.rb:9:in
block in <top (required)>': undefined method
stub_request' for < Class :0x007f8159bbe7c0> (NoMethodError)
SOLUTION:
Thanks to @gotva for telling me about stubs requirement to reside within it
blocks. Here is my new, fixed webmock test, and it works great:
context "when token is nil it" do
it "called refresh method" do
YouTube.any_instance.should_receive(:refresh_auth_token).with(data["refresh"])
YouTube.new(data["uid"], nil, data["refresh"])
end
it "refreshed the authentation token" do
stub_request(:post, "https://accounts.google.com/o/oauth2/token")
.with(:body => { "client_id" => CLIENT_ID,
"client_secret" => CLIENT_SECRET,
"grant_type"=>"refresh_token",
"refresh_token" => data["refresh"], }
).to_return(:status => 200,
:body => File.read("#{$fixtures}/refresh_token.json"))
yt = YouTube.new(data["uid"], nil, data["refresh"])
yt.token.should == data["access_token"]
end
end
It seems to me that using this stub
FooBar.stub(:foo).and_return("bar")
you are trying to stub nonexistent method.
Method foo
is instance method but you stub class method.
If you would like to stub instance method FooBar#foo use any_instance
FooBar.any_instance.stub(:foo).and_return("bar")
Update from comments
Apply stub
in it
or before
blocks.
new variant:
it 'place here some description for method foo' do
FooBar.any_instance.stub(:foo).and_return("bar")
expect(FooBar.new.foo).to eql('bar')
end
or
# the order is important!
describe "FooBar" do
before { FooBar.any_instance.stub(:foo).and_return("bar") }
subject { FooBar.new }
its(:foo) { should == "foo"}
end