FakeTTP

Purpose

When you are writing acceptance/integration tests for an application which makes HTTP requests to a remote application, sometimes you need to be able to test the interactions in different scenarios without talking to a real instance of the remote application.

FakeTTP is a standalone web application that allows you to mock requests (ie set and verify expectations on the requests your application makes, and return suitable responses to those requests).

Installation

Install the gem

Add GitHub as a gem source (you only need to do this once):

gem sources -a http://gems.github.com

Then install FakeTTP:

sudo gem install kerryb-fakettp

Alternatively, you can specify the source when you install the gem:

sudo gem install kerryb-fakettp --source http://gems.github.com

Create a FakeTTP directory

You can install FakeTTP anywhere that your web server user can see it:

fakettp install <directory>

Point your web server at the directory

FakeTTP should work with any Rack-compatible server: just point the server to the correct directory. For example, using Passenger (mod_rails) with Apache, create a virtual host along these lines:


  <VirtualHost *:80>
    ServerName fakettp.local
    DocumentRoot "/path/to/fakettp/public"
    <directory "/path/to/fakettp/public">
      Order deny,allow
      Deny from all
      Allow from 127.0.0.1
    </directory>
  </VirtualHost>

Then make sure fakettp.local resolves to 127.0.0.1 (assuming you’re running the simulator on the same machine as the application under test), eg by adding the following line to /etc/hosts:

127.0.0.1 fakettp.local

IMPORTANT: security note

Because expectations are set by posting Ruby code to be executed on the server, you probably don’t want any old Tom, Dick or Harry to be able to connect. The security settings in the virtual host config example above restrict access to clients running on the local machine.

Usage

Resetting

To reset FakeTTP (ie remove all expectations and errors), make an HTTP POST request to http://fakettp.local/reset.

Setting expectations

To create a new expectation, make an HTTP POST request to http://fakettp.local/expect, with a Content-Type header of ‘text/plain’ and the request data containing a Ruby block to execute.

The supplied code should be in the following format, and will generally consist of a number of assertions on the request, followed by creation of the response to return to the application under test.


  expect "GET of /foo" do
    request.host.should == 'fakettp.local'
    request.path_info.should == '/foo'
  
    content_type 'text/plain'
    "All is well\n"
  end

The label on the first line is used in error reporting.

The expectation code has access to the underlying Sinatra request and response objects etc, as well as RSpec matchers.

Verifying

To verify that all expectations have been met, make an HTTP GET request to http://fakettp.local/verify.

If all is well, the response will be a 200 OK with a body of ‘OK’. Otherwise the status will be 400 Bad Request, with a list of failures in the body. The failure messages include the complete details of the unexpected request that was received, to assist debugging.

Multiple hosts

To have FakeTTP respond to multiple hostnames, create the appropriate hosts entries. If you’re using name-based virtual hosts in Apache, add a ServerAlias entry to the virtual host config, under the ServerName line, eg:

ServerAlias foo.com bar.com

Change log

0.2.4.1 (5 May 2009)

  • Temporarily depend on edge version of Sinatra, to gain Rack 1.0 compatibility.

0.2.4 (25 Mar 2009)

  • Fixed a bug which caused expectations to be run in the wrong order if there were more than nine of them.

0.2.3 (19 Mar 2009)

  • Fixed a bug where expectations were being overwritten on Linux due to Dir.entries not returning results in the expected order

0.2.2 (18 Mar 2009)

  • Only accept control requests (reset, expect, verify) on fakettp.local

0.2.1 (17 Mar 2009)

  • Fixed issue where rspec matchers weren’t available to expectations

0.2 (14 Mar 2009)

  • Complete rewrite, with tests and classes and stuff this time.

If you get an ‘unexpected return’ error, remove the return statement from your expectation, and just put the return value on the last line of the expect block.

0.1.2 (13 Feb 2009)

  • Make sure README.html appears in generated gem

0.1.1 (13 Feb 2009)

  • Fix permissions on installed tmp directory.

0.1.0 (13 Feb 2009)

  • First release as a gem.

To Do

  • Add examples
  • Make control requests RESTful?
  • Make main hostname configurable?
  • Show label in verification error for expected requests that weren’t received
  • Add facility to stub as well as mock requests
  • Allow more flexibility in request ordering
  • Allow user-specific helper files in installation dir
  • Check install/run behaviour when development dependencies are not installed
  • Provide Ruby API to set expectations etc
  • Return the expected content type even if expectation fails