Andrew
Andrew

Reputation: 43113

Ruby: mock a local object to test module methods

Working in Sinatra, a local object request is created and made available to all views and helpers. So, I can make an ApplicationHelper module with helper methods, and if the helper methods are called in the view they can in turn call the request object, like so:

module ApplicationHelper
  def nav_link_to(text,path)
    path == request.path_info ? klass = 'class="current"' : klass = ''
    %Q|<a href="#{path}" #{klass}>#{text}</a>|
  end
end

Now, I want to test this, but in my test the request object doesn't exist. I tried to mock it, but that didn't work. Here's my test so far:

require 'minitest_helper'
require 'helpers/application_helper'

describe ApplicationHelper do

  before :all do
    @helper = Object.new
    @helper.extend(ApplicationHelper)
  end

  describe "nav links" do
    before :each do
      request = MiniTest::Mock.new
      request.expect :path_info, '/'
    end

    it "should return a link to a path" do
      @helper.nav_link_to('test','/test').must_equal '<a href="/test">test</a>'
    end

    it "should return an anchor link to the current path with class 'current'" do
      @helper.nav_link_to('test','/').must_equal '<a href="test" class="current">test</a>'
    end
  end
end

So, how can you mock a 'local' object so that the code your testing can call it?

Upvotes: 2

Views: 1293

Answers (1)

Andrew Haines
Andrew Haines

Reputation: 6644

You need to make sure there is a request method on your @helper object that returns the mock request object.

In RSpec I'd just stub it. I'm not particularly familiar with Minitest, but a quick look suggests that this might work in recent versions (if you change request to @request in your before :each):

it "should return a link to a path" do
  @helper.stub :request, @request do
    @helper.nav_link_to('test','/test').must_equal '<a href="/test">test</a>'
  end
end

Update

Since Minitest requires that the stubbed method is already defined on the object, you could make @helper an instance of Struct.new(:request) instead of Object, i.e.

@helper = Struct.new(:request).new

And actually, having done that, you might not need the stub at all! You could just do

before :each do
  @helper.request = MiniTest::Mock.new
  @helper.request.expect :path_info, '/'
end

Upvotes: 2

Related Questions