---
title: ActiveResource and Testing
teaser:
tags: web,rails,testing
author: Eric Mill
published_on: 2007-02-02
---

`ActiveResource` is a pretty amazing implementation of <abbr
title="Representational State Transfer">REST</abbr>, made in Ruby, for Rails.
By the Rails core.  Invented by DHH.  It's got good credentials.  Sadly, it did
not make it into Rails 1.2, so there is tons of buzz about it, but very little
in the way of actual resources and active discussion.  The only thorough
treatment of `ActiveResource` out there I can find is by a Rails core member,
and it's good.  I'm not going to re-cover everything it says, so definitely
check it out.

[Taking ARes Out For a Test Drive][drive]

[drive]: http://weblog.techno-weenie.net/2006/12/12/taking-ares-out-for-a-test-drive

The idea is that you can do something like this:

```ruby
class User < ActiveResource::Base
  self.site = "https://thoughtbot.com"
end

u = User.find 1
u.email = "new@email.com"
u.save
```

By declaring a model in your app as inheriting from `ActiveResource::Base` (as
opposed to `ActiveRecord::Base`), you get to work with remote objects as if they
were local.  `User.find` is doing a `GET` request to `/users/1.xml` (at
https://thoughtbot.com in this example), and `u.save` is doing a `PUT`
request to /users/1.  The `PUT` is actually a `POST` with a parameter
`_method=put`, but its heart is in the right place.  Of course, the site you're
getting objects remotely from has to support this, and the easiest way to do
this is with the new [map.resources] helpers that did make it into Rails 1.2.

[map.resources]: https://archives.ryandaigle.com/articles/2006/8/1/whats-new-in-edge-rails-simply-restful-support-and-how-to-use-it

Now I have the opportunity to use `ActiveResource` at work, and I get to do it
in the most educational way I can think of&#8212;replacing a developed local
`User` model with a remote `User` model.  Naturally, I have pre-existing tests
written that I need to have pass in order for the refactor to be considered
complete.  The idea is that permissions for this app (and other, sister apps)
will all be governed by a parent application, and each child app gets the
permissions for the logged in user from the parent app.  We decided the easiest
way was by sharing the `User` model through `ActiveResource`.

I don't need to change any user data, or search by anything but ID, so I really
only need a show action implemented.  And, because I'm not just replacing a
`User` model, but also a `Role` model (`User has_many :roles`), I'm going to
have to return additional data in the `User` object that acts like the `Role`
model I used to have.  I also have to omit certain fields in the remote `User`
model that aren't appropriate for the child app to know.  Since it's only one
action, and it's going to have to contort the data, I don't want to do
`map.resources` and override the remote `User` model's `to_xml`
function&#8212;it makes more sense to just make my own .rxml view and fake the
resource.  `ActiveResource`'s `to_xml` format is very easy to fake, even
including a `has_many` relationship.

At `/tools/:tool_id/users/:id.xml`:

```ruby
xml.instruct!
xml.user do
  xml.email @user.email
  xml.tag! "first-name", @user.first_name
  xml.tag! "remote-id", @user.remote_id, :type => "integer"

  xml.roles do
    @user.roles_in(@tool).each do |role|
      xml << role.to_xml(:skip_instruct => true, :only => [:title, :context])
    end
  end
end
```

How to best test your `ActiveResource` models is an open question right now, as
far as I can tell.  There's no documentation, or even blog posts, that I can
find, but there is an http\_mock file included with `ActiveResource`, that is
used in `ActiveResource` in its own tests, to test itself.  The setup in
`ActiveResource`'s test file for `Base` looks (something) like this:

```ruby
def setup
  @matz  = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
  @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')

  ActiveResource::HttpMock.respond_to do |mock|
    mock.get    "/people/1.xml",  {}, @matz
    mock.get    "/people/2.xml",  {}, @david
    mock.put    "/people/1.xml",  {}, nil, 204
    mock.delete "/people/1.xml",  {}, nil, 200
    mock.get    "/people/99.xml", {}, nil, 404
    mock.get    "/people.xml",    {}, "<people>#{@matz}#{@david}</people>"
  end
end
```

This approach is interesting, because instead of mocking out the behavior of the
`Person` model, they're creating a mock Internet for the `Person` model to talk
to.  And, instead of using <abbr title="Yet Another Markup Language">YAML</abbr>
fixtures, they're using <abbr title="Extensible Markup Language">XML</abbr>
fixtures.  And, because `ActiveResource`'s <abbr title="Extensible Markup
Language">XML</abbr> format is so simple, they're just making a hash with a root
and calling `to_xml`, and that's fine.  That's a lot to take in.

So here's my method for integrating `ActiveResource`s into my unit and
functional tests, which for me only involved editing test\_helper, and required
no change to any functional or unit test files.  I'm sure it's not the best
possible method, but it achieves my goal of not changing how I write unit and
functional tests.  Here's an excerpt of my test\_helper.rb:

```ruby
def self.all_fixtures
  fixtures :other, :normal, :models
  remote_fixtures
end

def self.user(name)
  path = File.join(RAILS_ROOT, "test", "remote_fixtures", "users", "#{name.to_s}.xml")
  return nil unless File.exists?(path)
  File.read path
end

def self.remote_fixtures
  ActiveResource::HttpMock.respond_to do |mock|
    mock.get "/tools/1/users/2.xml", {}, user(:eric)
    # some ActiveResource requests append these empty parameters, in any order
    # and you can't seem to use regexps with HttpMock right now
    mock.get "/tools/1/users/2.xml?include=&conditions=", {}, user(:eric)
    mock.get "/tools/1/users/2.xml?conditions=&include=", {}, user(:eric)
    mock.get "/tools/1/users/3.xml", {}, user(:matt)
    mock.get "/tools/1/users/4.xml", {}, user(:paper)
    mock.get "/tools/1/users/0.xml", {}, nil, 404
    mock.get "/tools/1/users/.xml", {}, nil, 404
  end
end

def users(name)
  case name
  when :eric
    User.find(2)
  when :matt
    User.find(3)
  when :paper
    User.find(4)
  else
    nil
  end
end
```

This is assuming I have <abbr title="Extensible Markup Language">XML</abbr>
files in test/remote\_fixtures/users, named eric.xml, matt.xml, and paper.xml,
that are the mock responses I want `ActiveResource` to think it is getting.

The primary drawback here is that I'm hard-coding specific fixture info into
test\_helper.  I could address some of this by doing part of the logic
dynamically, by reading filenames in the test/remote\_fixtures/users directory.
The secondary drawback is that you need to make sure remote\_fixtures is being
called in every test file.  Since I was already using an all\_fixtures helper at
the top of each file to load in my <abbr title="Yet Another Markup
Language">YAML</abbr> fixtures, I just included a call to remote\_fixtures
inside that, and I didn't have to add anything.

`ActiveResource` is not at all meant to be ready for release, so any issues I
have with it should not be taken as complaints, just as information to be aware
of if you go to use it.  The main issue that makes this process difficult is
that every possible route `ActiveResource` could request needs to be listed in
`HttpMock`; there's no support for regular expressions.  Depending on your app,
there could be requests made to /users/.xml, or /users/0.xml, and if there is no
mock route specified, an error will be thrown and it will halt your tests.
Sometimes requests are made with empty parameters, like `?include=&condition=`.
I'm not clear yet on when this happens, but it does.  Of course, using
`HttpMock` may not be at all the way the developers of `ActiveResource`
ultimately intend us to test `ActiveResource` objects; perhaps we will actually
mock out the objects or the model, instead of The Internet.

Overall, my transition to using `ActiveResource` has gone very smoothly.  The
implementation is a beautiful example of the kind of convenience that <abbr
title="Representational State Transfer">REST</abbr> is supposed to bring us.
Even if it's not part of Rails 1.2, I think it's ready to be used, in at least
small applications, right now.
