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
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-cucumberI''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 Doel
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 Doel <mike at mikedoel.com> wrote:> > 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 Doel > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- 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"
I followed Bryan''s pattern here, and let RSpec reset everything. http://www.brynary.com/2009/2/3/cucumber-step-definition-tip-stubbing-time On May 4, 2009, at 3:13 AM, aslak hellesoy wrote:> > 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
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 On Sunday, May 3, 2009, Matthew Van Horn <mattvanhorn at gmail.com> wrote:> 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 > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
My absolute favorite solution for this: http://github.com/chrisk/fakeweb/tree/master 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 Maddox <pat.maddox at gmail.com> wrote:> 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 > > On Sunday, May 3, 2009, Matthew Van Horn <mattvanhorn at gmail.com> wrote: >> 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 >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- Bill Kocik http://bkocik.net
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. On May 5, 2009, at 12:34 PM, Pat Maddox wrote:> 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 > > On Sunday, May 3, 2009, Matthew Van Horn <mattvanhorn at gmail.com> > wrote: >> 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 >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users