Mocking class method during require

12 views
Skip to first unread message

Zach Hamman

unread,
Jan 26, 2023, 4:30:24 AM1/26/23
to rspec
Hello,
I have a class that includes a module from a gem and leverages a class method from the module:

class A
  include ThirdPartyGem::ModuleName

  method_from_module option1: 'a thing', option2: 384
end

My spec test looks like:

require 'spec_helper'
require 'a'

Rspec.describe A do
...
end

I want to know how i can mock "method_from_module" since it would get executed on the "require" in the spec.  There are instance methods that I want to test but for brevity I have left those out of the examples above.  I was trying to think about using "class_double" in RSpec.configure, but I still intend on testing that class.

Thanks for any ideas.


Jon Rowe

unread,
Jan 26, 2023, 4:37:16 AM1/26/23
to rspec
You basically can't mock this in a sensible fashion with rspec-mocks because all of our mocking suite is predicated on already having loaded the class, at which point your method has already been invoked. Even if you could control the loading and pre-emptively mock it during loading rspec-mocks are not designed to survive across tests and loading classes happens only once so would leak mocks amongst tests.

Why are you attempting to mock this method?

One of the general peices of advise with mocking is not to mock things you don't own, so if the answer is to make assertions upon what including the gem does, you are better off making those assertions based on the result rather than mocking it.

If the answer is because it makes some expensive API call you'd like to avoid in tests, I would suggest instead either using something like VCR to mock out the API call, (which would have to be done before loading 'a') or to instead subsitute this module entirely for a fake "test adapter" you control in its entirity (an implementation of the adapter pattern).

Cheers
Jon

Zach Hamman

unread,
Jan 26, 2023, 10:44:33 AM1/26/23
to rspec
That was my gut instinct too.  The "method_from_module` is a configuration method.  No external calls to any APIs.  My goal was to reduce the dependency injection in the test itself because the gem and the class method are not necessary for the unit tests.  I just didn't want to have to do require 'third_party_gem' in the test as well.

Jon Rowe

unread,
Jan 26, 2023, 11:01:21 AM1/26/23
to rspec
You could use a `class_double` collaborator instead of `A` but the gem and the class method are a part of `A` the way you are using them, so a unit test should include them, mocking it out would change the behaviour of `A` and could have side effects you can't forsee.
Reply all
Reply to author
Forward
0 new messages