Stubbing Net::HTTP.get

Liquid error: undefined method `login' for nil:NilClass : January 12th, 2006

UPDATE: Aslak noted that I'm not actually using mocks but stubs. The distinction appears to be in the use of expectations set on your mock object. Anyway, read more at [Martin Fowler's Bliki](http://www.martinfowler.com/articles/mocksArentStubs.html). So the classic rails example: you're writing a blog. Maybe you've decided you want to be able to add feeds of your buddies Slash and Dingo to your sidebar so that their latest content shows up there. You sit down to bang out code but because you're working to improve your code practices you decide to write tests first. How do you write tests against information that might change or you don't always have access to in development? Stubbing to the rescue. Stubs are a bit like fixtures outside of the database. We have some sort of information that our queries should return, so we stub those responses and are able to run our tests on our code without changing the application. In our case, we're using something like this in our blog model to fetch our RSS feed and parse it.
1
2
3
4
5
6
7
8
9
10

  def fetch
    uri = URI.parse(self.rss_url)
    http = Net::HTTP.new(uri.host,uri.port)
    if !uri.query.nil?
      rss = SimpleRSS.parse http.get(uri.path + '?' + uri.query, 'User-Agent' => 'glu.ttono.us/1.0').body
    else
      rss = SimpleRSS.parse http.get(uri.path, 'User-Agent' => 'glu.ttono.us/1.0').body
    end
  end
When we run tests the application shouldn't actually hit the website, so we'll stub out the methods that do that. In our case, Net::HTTP.get (Note: Net::HTTP.new doesn't actually make a connection). What we'd like is to be able to have the request actually return information in a file that we've defined, so the call to get should return the file and the call to body should give us the contents. Here's an easy way to implement that.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

require 'net/http'

module Net
  class HTTP
    def get(path, *args)
      return File.open("#{RAILS_ROOT}/test/mocks/test/#{File.basename(path)}")
    end
  end
end

class File
  alias_method :body, :read
end
Shove it in your test/mocks/test directory, and write your test cases. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

require File.dirname(__FILE__) + '/../test_helper'
require File.dirname(__FILE__) + '/../mocks/test/http'

class BlogTest < Test::Unit::TestCase
  fixtures :blogs, :items

  def test_fetch
    num_items = Item.count
    b = blogs(:gluttonous_with_sample_feed)
    
    assert_equal 0, b.items.count
    
    b.fetch
    
    assert_equal num_items + 10, Item.count
    assert_equal 10, b.items.count
  end
end
See Scott Baron's article [Mockery](http://scott.elitists.net/users/scott/posts/mockery) for information on Mocks (no, not stubs) in a more general Ruby sense.

4 Responses to “Stubbing Net::HTTP.get”

  1. rick Says:
    The fun part is you get to create your own User Agent!
  2. Kev Says:
    It's true!
  3. Aslak Hellesoy Says:
    You're not mocking, but stubbing. http://www.martinfowler.com/articles/mocksArentStubs.html
  4. Ryan Platte Says:
    This has code smell to me. I wrote about my concerns on my blog: Why Rails bugs me, part 1: test/mocks

Sorry, comments are closed for this article.