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.
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.