Dupe

There are lots of great tools out there to ease the burden of prototyping ActiveRecord objects while cuking your application (e.g., thoughtbot’s “Factory Girl”). But what about prototyping ActiveResource records? That’s where Dupe steps in.

Installation

First, install the gem:

# gem install moonmaster9000-dupe

Then add this to your cucumber.rb environment (config/environments/cucumber.rb)

config.gem 'moonmaster9000-dupe', :lib => 'dupe'

You might also want to add a particular version number if you want to make sure a particular feature is there:

config.gem 'moonmaster9000-dupe', :lib => 'dupe', :version => '>=0.3.0'

Example

Let’s suppose your cuking a book search application for a library that consumes a RESTFUL book datastore service via ActiveResource. You might start by writing the following feature in RAILS_ROOT/features/library/find_book.feature:

Feature: find a book
  As a reader
  I want to search for books
  so that I can check them out and read them. 

Scenario: search by author
  Given an author "Arthur C. Clarke"
  And a book "2001: A Space Odyssey" by "Arthur C. Clarke"
  When I search for "Arthur C. Clarke"
  I should see "2001: A Space Odyssey"

To get this to pass, you might first create ActiveResource models for Books and Authors that connect to the Library service:

class Book < ActiveResource::Base
  self.site = 'http://bookservice.domain'
end

class Author < ActiveResource::Base
  self.site = 'http://bookservice.domain'
end

Then you might create the following resource definition via Dupe.define (put it in a file with a .rb extension and place it in RAILS_ROOT/features/support/):

Dupe.define :book do |book|
  book.author do |author_name|
    Dupe.find(:author) {|a| a.name == author_name}
  end
end

and the following cucumber step definitions (utilizing Dupe.create):

Given /^an author "([^\"]*)"$/ do |author|
  Dupe.create :author, :name => author
end

Given /^a book "([^\"]*)" by "([^\"]*)"$/ do |book, author|
  Dupe.create :book, :title => book, :author => author 
end

Dupe.create will in turn mock two service responses for each resource. For example, for the Book resource, it will mock:

# Book.find(:all) --> GET /books.xml
<?xml version="1.0" encoding="UTF-8"?>
<books type="array">
  <book>
    <id type="integer">1</id>
    <title>2001: A Space Odyssey</title>
    <author>
      <id type="integer">1</id>
      <name>Arthur C. Clarke</name>
    </author>
  </book>
</books>

# Book.find(1) --> GET /books/1.xml
<?xml version="1.0" encoding="UTF-8"?>
<book>
  <id type="integer">1</id>
  <title>2001: A Space Odyssey</title>
  <author>
    <id type="integer">1</id>
    <name>Arthur C. Clarke</name>
  </author>
</book>

From here, you could start scaffolding your controllers, with the assumption that Dupe will mock the responses to Book.find(<id or :all>) and Author.find(<id or :all>).

More

Dupe supports attribute defaults, attribute transformations, stubbing, resource associations, custom resource mocks, and more. Want to learn more? Consult the API documentation at moonmaster9000.github.com/dupe/api/