rspec 3 - stub a class method
You should do
allow(MyMod::Utils).to receive(:find_x).and_return({something: 'testing'})
Check out the doco Method stubs.
How to mock class method in RSpec expect syntax?
Here's what you want to do (no need for double
):
allow(Facebook)
.to receive(:profile)
.with("token")
.and_return({"name" => "Hello", "id" => "14314141", "email" => "hello@me.com"})
stubbing a class method inside a method in rspec to return true
Ensure the syntaxing of mocking the return value is correct:
allow(SiteLicenseService).to
receive(:get_package_for_site_license).and_return(true)
In Ruby, classes are written in TitleCase and methods are written in snake_case. The method to be received should be a :symbol.
RSpec - mock a private class method call inside a request spec?
You're mocking on the class, which is how you mock you "static" class-level methods. For example, if your method was def self.foo
and you called it via MyClass.foo
, then allow(MyClass)
is the way to go.
Your method is not a class-level method, it's an instance method. You invoke it by first creating an instead of MyClass
and then calling the method on that instance. You need to use allow_any_instance_of
to mock the method for all future instances of the class:
allow_any_instance_of(MyClass).to receive(....)
How to stub a class method using rspec/rspec-mocks
For your workflow, I think it's going to work better to use a class_double
than than to stub the Hashes
class directly. allow(Hashes)
is always going to require that the Hashes
constant is defined. It's simply how Ruby works and RSpec can't do anything about that. With a class double, you can instead do this:
class_double("Hashes", :calculate_hash => canned_return_value).as_stubbed_const
# or
hashes = class_double("Hashes").as_stubbed_const
allow(hashes).to receive(:calculate_hash) do |file|
# look up what to return
end
class_double("Hashes")
provides you with a test double that, when the Hashes
constant is defined, will verify the mocked and stubbed methods against the Hashes
class definition, but when it is not defined, will act just like a normal double that allows anything to be mocked or stubbed on it. The as_stubbed_const
bit tells rspec-mocks to stub the Hashes
constant for the duration of the example so that any references to Hashes
get your class double rather than the real Hashes
class, even if the Hashes
class has never been defined.
Stub a 'nested' class method that is called by a wrapper method (RSpec Mocks)
You may want to use RSpec's allow(...)
to stub the intermediate method. This is also useful for testing logic flow or for mocking third-party services in tests.
For example:
expected_response = 'This is a different string'
allow(Thing).to receive(:method_three).and_return(expected_response)
Then expect(Thing.method_one('Hi')).to eq(expected_response)
should pass.
See https://relishapp.com/rspec/rspec-mocks/v/2-14/docs/method-stubs for more information on stubbing methods.
Is there a way to stub all methods of a particular class in RSpec 3?
Yes, stub_everything
is deprecated.
Yes, you can use as_null_object
to stub everything in your test like this:
let(:push_service) { double(PushService).as_null_object }
When you use as_null_object
, your object will respond to any method that is not implemented. It will also allow you to use explicit stubs and explicit expectations.
See Null object doubles documentation for more information.
How do I stub a class method with a class_double in RSpec?
class_double
doesn't actually replace the constant. You can call as_stubbed_const
to replace the original
class_double("Project").as_stubbed_const
This is the just a convenience wrapper around stub_const
How to stub class instantiated inside tested class in rspec
Reaching for DI is always a good idea (https://stackoverflow.com/a/51401376/299774) but there are sometimes reasons you can't so it, so here's another way to stub it without changing the "production" code.
1. expect_any_instance_of
it 'uploads to google cloud' do
expect_any_instance_of(Google::Storage).to receive(:insert_object)
worker = UploadWorker.new
worker.perform
end
In case you just want to test that the method calls the method on any such objects.
2. bit more elaborated setup
In case you want to control or set up more expectations, you can do this
it 'uploads to google cloud' do
the_double = instance_double(Google::Storage)
expect(Google::Storage).to receive(:new).and_return(the_double)
# + optional `.with` in case you wanna assert stuff passed to the constructor
expect(the_double).to receive(:insert_object)
worker = UploadWorker.new
worker.perform
end
Again - Dependency Injection is clearer, and you should aim for it. This is presented as another possibility.
Related Topics
Fastest Way to Check If a String Matches a Regexp in Ruby
How to Backreference in Ruby Regular Expression (Regex) with Gsub When I Use Grouping
Ruby - Keyword Arguments - Can You Treat All of the Keyword Arguments as a Hash? How
How to Make Carrierwave Delete the File When Destroying a Record
Why Is Ruby Unable to Verify an Ssl Certificate
How to Get Elapsed Time in Milliseconds in Ruby