0

I'm working on a project in Ruby on Rails. We have a controller action that uses a module within a gem. This gem isn't finished yet and it isn't on the file system.

I was told to mock the module in order to test the controller. Is there a way to test this without the actual gem? Would mocking the 'require' calls work? We are currently using Mocha for Mocking and Stubbing.

There is a way to mock the imports in python. Maybe there is a similar answer to mocking the requires in ruby. How to mock an import

Or please let me know what would be the best way to handle this.

Update: The person who told me to mock it, suggested adding a stub file, but that would require adding test code to the controller and I don't want to do that.

Update 2: The controller uses methods declared in the Module.

Community
  • 1
  • 1
ieldanr
  • 670
  • 6
  • 12
  • 1
    If someone told you to mock it, and you don't know how, why not ask that person how to do it? – the Tin Man Apr 05 '13 at 17:40
  • I asked the person. He suggested adding a stub file, but I would need to require it in the controller, and I prefer not to corrupt the controller with test code. – ieldanr Apr 05 '13 at 17:52
  • Does the controller actually need anything in the module to function? If not, just define it as an empty module before you load the controller, or if you're testing the full stack, before you load the rails environment. – Zach Kemp Apr 05 '13 at 18:10
  • Yes. The controller needs the methods declared in the module. I'm trying to make the tests pass without having the module files. – ieldanr Apr 05 '13 at 18:21
  • Also I would suggest to your colleague that you should not be testing controllers (other than with integration tests). If you've got enough code in your controller to require unit tests... you've got too much code in your controller. – Russell Apr 05 '13 at 19:45
  • Well the thing with this controller is that it makes 3-4 API calls to another system. We are only displaying the information returned. Would it be better to put in a model? – ieldanr Apr 05 '13 at 21:12

2 Answers2

0

If you are writing tests to mock the method calls, they would fail. For example,

controller.should_receive(:method_in_non_existent_module).with(args) #=> errors

In a correct Red->Green TDD scenario , this is alright because the next step would be to require the gem/file, include the module and add the method call in the controller and make the test pass. But you'll not be able to make the tests pass since you can't require the file because it doesn't exist yet.

May be the developer who asked you to mock the method meant to do so not in your tests, but in your actual code. For example, he's writing a gem 'dongle-jokes' which has a method that gets the most popular dongle joke from the most recent tech conference. He doesn't want the gem to be a blocker for you to finish the controller and the views so he asks you to use a dummy interface that spits out a dummy response.

  1. Write the tests that fail
  2. Add a file lib/dongle-jokes.rb
  3. Add the following to that file.

    module DongleJokes
      def joke
        "Dongle jokes aren't funny!"
      end
    end
    
  4. Require the file and include the module, use the method in the controller.

The test should pass now. You can remove lib/dongle-jokes.rb when you start using the actual gem.

Emil
  • 1,240
  • 1
  • 15
  • 27
  • Do we really have to bring up the PyCon thing even in StackOverflow answers? – Russell Apr 05 '13 at 19:50
  • @Russell We don't have to , if you can look at it as just an example to explain the answer :) – Emil Apr 05 '13 at 20:15
  • This answer is also correct. This is actually what my colleague suggested. I ended up doing something similar: stub file in tests directory, require the stub file in the tests and mock the methods in the test. This allowed me to write code in the controller without the actual module (: – ieldanr Apr 05 '13 at 20:30
  • @ieldanr Why do you have to require the file in the test ? Just require the file in the first line of the controller and it should work, I guess. The test should ideally have no idea about the fake module. After you swap the fake module with the actual gem, the tests shouldn't have to be touched and should still pass, that's the idea. – Emil Apr 05 '13 at 20:43
0

If you're working in Rails you shouldn't need to add a require to the controller anyway, as when you add the gem to your gemfile it will be required automatically on Rails startup.

What your colleague most likely meant was that you should stub the module itself. Are you using rspec for your tests? If so you should be able to use stub_const. Let's say the module is called Payments. You can then write test code like the following:

before do
  stub_const("Payments", stub)
  Payments.stub(process: "payments successful")
end
Russell
  • 12,261
  • 4
  • 52
  • 75
  • You answer looks correct! That is what I'm looking for: 'stub the module istelf'. unfortunately, we aren't using rspec. Do you know how to do that with Minitest and Mocha? – ieldanr Apr 05 '13 at 20:24