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.
Related videos on Youtube
Juergen
Updated on September 16, 2022Comments
-
Juergen over 1 year
I am using rspec-mock for test-driven-development. I am starting implementing a single class and mocking/stubbing the other classes using rspec-mock. Mocking objects of classes yet to be implemented works well. However when I try to mock a class method of a class that does not exist yet, I haven't been successful. My class "Hashes" should have a class method "calculate_hashes" receiving a filename and returning a hash.
I tried
allow(Hashes).to receive(:calculate_hash) do |file| # looks up what to return end
which give the error "Hashes is not a class". I then implemented a class "Hashes"
class Hashes end
and then only tried to stub the class method in the same way. This gives the error "Hashes does not implement: calculate_hash" When I then add the method to my class definition:
class Hashes def self.calculate_hash(filename) end end
it finally works and my stubbing of this class method works using "allow(Hashes)" as seen in the example above. I just wonder if there is a way of accomplishing this without writing this class skeleton.
Or am I maybe trying to accomplish something in an inappropriate way? Or is rspec-mock maybe not the right tool to do this?
Any help is greatly appreciated.
-
Juergen almost 9 yearsOk, that works, thanks! However, I wonder how I would approach an example where I would need a class method and an instance method. e.g.
new_book = Book.new\ content = new_book.read_page(5)
Do I first need to mock the object usingbook_object = double("Book")\ allow(book_object).to receive(:read_page).and_return(...)
and then mock the class bybook = class_double("Book")\ allow(book).to receive(:new).and_return(book_object)
Is this the way to go? -
Myron Marston almost 9 yearsIt's hard to read your question due to the comment formatting. Can you send your question to the RSpec mailing list? groups.google.com/group/rspec