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
In RSpec, a stub is often called a Method Stub, it's a special type of method that “stands in” for an existing method, or for a method that doesn't even exist yet. In our example, the allow() method provides the method stubs that we need to test the ClassRoom class.
The difference between mocks and stubsA Test Stub is a fake thing you stick in there to trick your program into working properly under test. A Mock Object is a fake thing you stick in there to spy on your program in the cases where you're not able to test something directly.
You can't mock an instance variable. You can only mock methods. One option is to define a method inside OneClass that wraps the another_member , and mock that method. However, you don't have to, there is a better way to write and test your code.
Generally speaking, a mock is a replica or imitation of something. RSpec mocks, in the same sense, are an imitation of return values or method implementations. The ability to carry out this kind of imitation makes it possible to set expectations that specific messages are received by an object.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With