Cucumber - when to stub/mock

I’m just curious about this, since my solution involved stubbing a
call to GeoIp.

Is there a good rule of thumb for when you make exceptions to the ‘no
stubbing’ philosophy of Cucumber?

My step was: “Given I am accessing the site from Japan,” but I can
think of other situations - mostly when interacting with web services,
that I’d probably want to stub something, rather than requiring a net
connection for testing.

thanks for any advice,
Matt Van Horn

I’m just curious about this, since my solution involved stubbing a call to
GeoIp.

Is there a good rule of thumb for when you make exceptions to the ‘no
stubbing’ philosophy of Cucumber?

This is the rule of thumb:
http://wiki.github.com/aslakhellesoy/cucumber/mocking-and-stubbing-with-cucumber

My step was: “Given I am accessing the site from Japan,” but I can think of
other situations - mostly when interacting with web services, that I’d
probably want to stub something, rather than requiring a net connection for
testing.

Your case might be special enough that the rule of thumb doesn’t apply.
If
you explain in more detail what’s going on I might be able to give some
more
advice on how to address it.

Aslak

On May 4, 2009, at 1:28 AM, aslak hellesoy wrote:

Is there a good rule of thumb for when you make exceptions to the
‘no stubbing’ philosophy of Cucumber?

This is the rule of thumb: http://wiki.github.com/aslakhellesoy/cucumber/mocking-and-stubbing-with-cucumber

I’m in a similar boat as Matt. My app does geocoding using Andre
Lewis’ excellent geokit gem (and the Rails plugin). That stuff hits
web-based geocoders (Google in my case). I also scrape other web sites.

So, in order to make my testing executable without a net connection
and avoid extra traffic on other folks’ sites from my tests, I stub
out the actual net call with code like this:

def stub_geocode_lookup(address,datafile)
@xml = File.read(RAILS_ROOT + “/spec/fixtures/geocodes/” + datafile)
response = MockSuccess.new
response.stubs(:body).returns(@xml)
stub_google_call(address,response)
end

def stub_google_call(address,response)
url = "http://maps.google.com/maps/geo?
q

#{Geokit
::Inflector
::url_escape
(address)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"

Geokit
::Geocoders
::GoogleGeocoder
.stubs(:call_geocoder_service).with(url).returns(response)
end

I also make use of FakeWeb in a couple places to do a similar thing
for the scraping of sites. I have a rake task that grabs fresh
versions of the pages I’m going to scrape and deposits it into my spec/
fixtures directory. If I run that every couple of days, I reduce my
risk of having my fixture data diverge too far from what the
production app actually sees.

Mike D.

It’s possibly worth pointing out for anyone else who needs to do
stubbing, that you don’t necessarily need a framework to stub stuff; I
have cucumber tests that stub out some setup code in my app*, and they
just use monkey-patching to do the stubbing.

For instance, in the example below, you could just do:
module Geokit
module Geocoders
class GoogleGeocoder
def call_geocoder_service(url)
… do whatever is needed to return appropriate test data
end
end
end
end

You could even use alias_method to rename the original
call_geocoder_service and call it if it got an unexpected url.

I’m not sure which is better - this at least saves you from a
dependency on an external stubbing/mocking framework. But it could be
seen as uglier.

  • Korny
  • I know, this is not ideal, but it’s testing a one-off migration
    script, and I didn’t really want to make the script setup code
    generic, just to make the tests cleaner.

On Mon, May 4, 2009 at 3:42 PM, Mike D. [email protected] wrote:

excellent geokit gem (and the Rails plugin). That stuff hits web-based
stub_google_call(address,response)
scraping of sites. I have a rake task that grabs fresh versions of the


Kornelis Sietsma korny at my surname dot com
“Every jumbled pile of person has a thinking part
that wonders what the part that isn’t thinking
isn’t thinking of”

Stubbing should be avoided when using Cucumber, if only because that
reduces its effectiveness as an integration testing tool. That doesn’t mean
stubbing is prohibited. You don’t really need to test Gooble. And Cucumber’s
specing and communication capabilities don’t suffer from stubbing.

One thing to be aware of when stubbing: There is no cleanup/revert logic
yet
in Cucumber. This means that if you stub a class method, it will remain
stubbed for subsequent scenarios. This means high risk of coupled
scenarios
and unpredictable behaviour if you run scenarios in different orders.

If you need a cleanup facility (remove stubbed methods after a
scenario),
please file a feature request.

Aslak

On Sun, May 3, 2009 at 10:42 PM, Mike D. [email protected] wrote:

I also make use of FakeWeb in a couple places to do a similar thing for the
scraping of sites.

FWIW, so does the maintainer of FakeWeb, Chris K. (with whom I
work).

Stubbing should be avoided when using Cucumber, if only because that
reduces
its effectiveness as an integration testing tool. That doesn’t mean
stubbing
is prohibited. You don’t really need to test Gooble. And Cucumber’s
specing
and communication capabilities don’t suffer from stubbing.

///ark

Don’t mock the Geolp library directly. Wrap it with an API that fits
your domain better. Then write a very simple object that implements
the same API but doesn’t hit the network. You can use a switch
somewhere in env.rb to use your fake implementation or the Geolp one.

Pat

I followed Bryan’s pattern here, and let RSpec reset everything.

http://www.brynary.com/2009/2/3/cucumber-step-definition-tip-stubbing-time

Actually, I do have my own object wrapping GeoIp, and I stubbed the
method on that object that returns a country code for me.
I can see maybe creating another object to be used in the test
environment, but I can’t see what advantages that offers over using
the rspec mocking framework.

My absolute favorite solution for this:

I use that in an application I’m building that uses Twitter’s OAuth,
and otherwise heavily uses the Twitter API. It allows me to easily
fake out all of Twitter’s responses so I can do
unit/integration/acceptance tests (with Cucumber and WebRat for the
latter) without touching the network.

As a matter of good practice, I always do this first:

FakeWeb.allow_net_connect = false

That ensures that any outbound HTTP requests that I forgot to fake out
will cause FakeWeb to blow up in my face and let me know that I’ve
missed something rather than silently letting it go by.

On Tue, May 5, 2009 at 12:34 PM, Pat M. [email protected]
wrote:

Is there a good rule of thumb for when you make exceptions to the ‘no stubbing’ philosophy of Cucumber?


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


Bill K.

http://bkocik.net