How to test a ruby application which uses mechanize

Viewed 3725

I wrote a small program that uses Mechanize to traverse a site.

I want to write tests for it, but don't want it to actually go log onto the site every time I run the tests. I would like to mock the internet, so that when it goes to some site, it simply returns the stored results.

Here is a small example, pretend my code's purpose was to pull links off of the google homepage, so I write a test to ensure the first link my code finds has the text "Images". I might write something like this:

require 'rubygems'
require 'mechanize'
require 'test/unit'

def my_code_to_find_links
  google = WWW::Mechanize.new.get('http://www.google.com')
  # ...
  # some code to figure out which links it wants
  # ...
  google.links
end

class TestGoogle < Test::Unit::TestCase
  def test_first_link_is_images
    assert_equal 'Images' , my_code_to_find_links.first.text
  end
end

How do I mock google.com so that I can test my_code_to_find_links without all the overhead of actually accessing the internet?

thanks -Josh

4 Answers

If you are writing functional tests and the server doesn't need to be anything fancy, you can write a little HTTP server that runs just for the test; the test code configures the code-under-test to contact the little HTTP server on localhost:<some_ephemeral_port>.

I recommend WEBrick. Putting up an HTTP server is a snap.

If you are writing unit tests then you are looking at the wrong end of the stick, you don't need to mock google.com but you should mock/stub Mechanize object, ie. a mechanize object is created, get method is called on the object with parameter http://www.google.com. And yes, you do need to test the operation you are performing on the result you get by visiting the page which you can easily do by a stubbed response and then doing all the test. For example if you are using mocha, then

mechanize = stub('WWW::Mechanize')
WWW::Mechanize.stubs(:new).returns(mechanize)
mechanize.stubs(:get).with('http://www.google.com').returns('What ever out put you are expecting so that you can test')

I don't think that you really need to test whether your request goes to google.com or not because that has already been tested in Mechanize gem.

On another note if you are doing integration/cucumber tests then you can use sinatra to fake the site. Sinatra makes it very easy to write a single page script and run that script as a website.

Edit:

If you are not using mocha then you need to install it and require it in your tests

sudo gem install mocha

And in your tests

require 'rubygems'
require 'mocha'

You can use Mechanize's test helpers too. Once Mechanize::TestCase is loaded no HTTP requests will be made outside mechanize itself. All requests are handled via WEBrick servlets.

Create a fixture, require the test cases and then stub/mock your request to return:

require 'mechanize/test_case'

...

Mechanize::TestCase.new('http://google.com').html_page(html_fixture)

For more options see: https://www.rubydoc.info/gems/mechanize/Mechanize/TestCase

Related