2

Right now I'm in the middle of a refactoring and I'm struggling with the following.

I have a class like this:

class Example
  def self.some_method
    if Rails.env.test?
      true
    else
      hit_external_service
    end
  end
 end

Now, I think mixing production code with test code into the class is not very good. We're using mocha, so I thought of removing the conditional logic and setting up a stub for the whole test suite, since this method gets called all over the place, like this:

class ActiveSupport::TestCase
  setup do
    Example.stub(:some_method).returns(true)
  end
end

But then when I want to test the original method I have to "unstub" it which seems very dirty as well, so I'm kind of stuck on how to do this.

I also thought of extracting the logic of hitting the external service to another class and then having that class as an injectable dependency, so for the whole test suite I could do:

Example.external_service = DummyImplementation

and then for the real tests I could do:

Example.external_service = RealImplementation

but this seems like overkill since the logic is only like 3 lines really.

So any suggestions? is there something simple that maybe I'm not seeing?

1 Answers1

1

For stubbing class methods, I usually create the stub in my specific test case that needs it, but then unstub the method on teardown. Like this:

require 'test_helper'

class MyTest < ActiveSupport::TestCase

  def teardown
    Example.unstub(:some_method)
  end

  test "not hitting the service" do
    Example.stub(:some_method).returns(true)
    assert Example.some_method
  end

  test "hitting the service" do
    assert Example.some_method
  end

end
steakchaser
  • 5,198
  • 1
  • 26
  • 34