Using Artifice to Stub Server Responses

In a recent project I needed a way to fake a response from a server in my Cucumber features. Specifically, I was testing integration with a payment gateway and wanted to stub it’s responses based on different requests.

In the past I have used FakeWeb, however it becomes a little hairy when you need to stub a response based on request body. I came across a couple of alternatives, firstly WebMock which looks promising but then Artifice from the mighty Yehuda Katz caught my eye…

Artifice lets you “replace the Net::HTTP subsystem of Ruby with an equivalent that routes all requests to a Rack application”. I like the simplicity of this solution as you can in essence use a Rack application to replace the responses of the service you are testing.

An Example

First we create a simple Rack application to stand in for the server we are interacting with.


app = proc do |env|
  [200, { "Content-Type"  => "text/html" },
    ["Hello world: #{env.inspect}"]
  ]
end

Then we simply use Artifice’s “activate_with” method to wrap any requests.


Artifice.activate_with(app) do
  response = Net::HTTP.start("google.com") do |http|
    http.post("/the_url", "foo=bar")
  end
  puts response.body
end

This allows for a Rack app to be used as a stand in for a complete API, it could be a Sinatra app for example allowing for easy route handling. We could go so far as to have a series of Rack apps that can be used as stand-ins for common API’s.

Why I stopped using Pickle with Cucumber

…no, not because it leaves a bitter aftertaste, I’m talking about the Pickle step definitions for Cucumber.

I have lately been using Pickle when writing Cucumber features, however I have come to the conclusion that this is a bad idea. The reason being that when using Pickle, you create entries directly, whereas the whole point of Cucumber is that it is for high level integration testing.

What I do now, is to create any entries by filling out and submitting the relevant forms with a step definition, for example I may have the following:

Given an admin has created the following products
  | Name    | Variants                                  | Featured |
  | T-Shirt | Small: 10.99, Medium: 12.99, Large: 14.99 | Yes      |
  | Keyring | Default: 2.99                             | Yes      |

I would then write a step definition for this that would log in as the admin user, break this table apart and fill in the relevant forms.

I would go so far as to say that using factories at all in features is a bad idea and instead everything should happen via the user interface for better coverage. For any data that is known to exist when the app is deployed via ‘rake db:seed’, this can be loaded in the ‘env.rb’ file e.g.


load 'seeds.rb'

Update 11/2/2010: Sometimes this is simply not practical due to slowdown which is a shame, as noted by Amos in the comments.

Unit testing by simplifying the problem: memoization

I see unit testing as a way to test each possible snippet of functionality and route the code in question can take. With Ruby being such a dynamic language and allowing shortcuts to common problems, sometimes it can seem somewhat of a mystery, how to test these snippets of functionality.

Using Memoization as an example:


class MyClass
  def lazy_initialized_value
    @lazy_initialized_value ||= Expensive.request
  end
end

There are actually 3 separate snippets of functionality that need testing here, however it is not immediately obvious from the example. Lets be slightly more verbose about what is actually happening:


class MyClass
  def lazy_initialized_value
    @lazy_initialized_value = Expensive.request unless @lazy_initialized_value
    @lazy_initialized_value
  end
end

Now it is much easier to see the 3 steps the code should take:

* Store result of expensive request in instance variable
* Leave instance variable alone when it is already set
* Return the value of the instance variable

Now we have this information, our tests become (using Mocha to mock external methods):


class Expensive; end

module Tests::MyClass
  # lazy_initialized_value
  # ----------------------
  class LazyInitializedValueTest < Test::Unit::TestCase
    def test_should_respond
      assert_respond_to MyClass.new, :lazy_initialized_value
    end
  
    def test_should_store_result_of_expensive_request_in_instance_variable
      instance = MyClass.new
      Expensive.stubs(:request).with().returns('expensive value')
      instance.lazy_initialized_value
      assert_equal 'expensive value', instance.instance_variable_get('@lazy_initialized_value')
    end
    
    def test_should_return_value_of_instance_varable
      instance = MyClass.new
      instance.instance_variable_set '@lazy_initialized_value', 'the value'
      Expensive.stubs(:request)
      assert_equal 'the value', instance.lazy_initialized_value
    end
    
    def test_should_maintain_existing_instance_variable_value_when_already_set
      instance = MyClass.new
      instance.instance_variable_set '@lazy_initialized_value', 'existing value'
      Expensive.stubs(:request)
      instance.lazy_initialized_value
      assert_equal 'existing value', instance.instance_variable_get('@lazy_initialized_value')
    end
  end
end

Now we have these tests in place, we can go back and refractor the code ’til our heart’s content using all the tricks in the book but by simplifying the problem in the first place, it gives us a solid test suite and the confidence to make changes without breaking functionality.

If you were solving this problem test-first then you wouldn’t (but more likely, shouldn’t) have written the first example until re-factoring stage anyway, however when these shortcuts become engrained in your brain, it’s all too easy to forget what they are _actually_ doing.

So there we go, simplify the initial implementation, get a solid test suite in order, _then_ re-factor.

Stubbing case statements with Mocha

I was happily mocking away with Mocha, then I passed a stub to a case statement at which point I was a little flummoxed.

The Ruby documentation clearly states that the ‘when’ in a ‘case’ statement uses the ‘===’ method for comparing the subject so I couldn’t work out why something like the following wasn’t working:


# Code
class A; end

def foo(instance)
  case instance
    when A : 'an A instance'
    else 'not an A instance'
  end
end

# Test
a = stub_everything
a.stubs(:===).with(A).returns(true)
assert_equal 'an A instance', foo(a)

So I had a little play around in irb and found the following:


class A; end
a = A.new
a === A #=> false
A === a #=> true

This revealed that I was actually stubbing the wrong side of the operator, I changed this to the following and voila!


# Code
class A; end

def foo(instance)
  case instance
    when A : 'an A instance'
    else 'not an A instance'
  end
end

# Test
a = stub_everything
A.stubs(:===).with(a).returns(true)
assert_equal 'an A instance', foo(a)

Looks obvious now but certainly wasn’t at the time!

Autotest Growl Fail/Pass Smilies

John Nunemaker posted a handy tip on “setting up autotest to work with Growl”:http://railstips.org/2007/7/23/autotest-growl-pass-fail-notifications

I use this all the time now however I didn’t like the ugly smilies (call me shallow if you like). I used “Wolfgang Bartelme’s”:http://bartelme.at “Smily Devkit”:http://bartelme.at/journal/archive/smiley_devkit to make a couple of PNG’s slightly more pleasing to the eye.

p=. !http://thelucid.com/files/fail.png(Autotest Fail image)!
!http://thelucid.com/files/pending.png(Autotest Pending image)!
!http://thelucid.com/files/pass.png(Autotest Pass image)!

The zip file can be downloaded here: “autotest_images.zip”:http://thelucid.com/files/autotest_images.zip

*Update* 17-08-07: Added ‘pending’ image for RSpec as requested by Aslak Hellesoy