CROSS-STUB makes cross process stubbing possible !!

Introduction

Existing mocking/stubbing frameworks support only stubbing in the current process. This is OK most of the time. However, when running cucumber integration test suite in non-webrat mode, these in-process stubbing frameworks simply doesn’t help. Eg. I want Time.now to always return a timing that should be a Sunday, how do I do that when running cucumber in selenium, culerity, steam, blah, blah mode? It doesn’t seem straight-forward me.

(Let’s not argue whether stubbing should be encouraged. It is an itch, the poor itch needs to be scratched.)

Getting Started

It’s hosted on gemcutter.org.

$ sudo gem install cross-stub

Setting Up

#1. If you are using rails, you are in luck:

$ ./script/generate cucumber
$ ./script/generate cross_stub

#2. Even if you are using something else, no worries:

# In the test setup method:
CrossStub.setup :file => <CACHE_FILE_PATH>

# In the test teardown method:
CrossStub.clear

# Find an entry point in your target application, eg. in a server, the
# point where all request handling starts:
CrossStub.refresh :file => <CACHE_FILE_PATH>

Using It

Using cross-stub is simple:

#1. Simple returning of nil or non-nil value:

class Someone
  def self.laugh
    'HaHa'
  end
end

Someone.xstub(:laugh)
Someone.laugh # yields: nil

Someone.xstub(:laugh, 'HoHo')
Someone.laugh # yields: 'HoHo'

#2. If a stubbed method requires argument, pass :xstub a proc:

Someone.xstub do
  def loves(other)
    "I love #{other}"
  end
end

Someone.loves('you') # yields: 'I love you'

#3. Something more complicated:

something = 'hello'
Someone.xstub do
  def do_action(who, action)
    %\#{who} #{action} #{something}\
  end
end

Someone.do_action('i', 'say') # failure !!

The above fails as a result of undefined variable/method ‘something’, to workaround we can have:

Someone.xstub(:something => 'hello') do
  def do_action(who, action)
    %\#{who} #{action} #{something}\
  end
end

Someone.do_action('i', 'say') # yields: 'i say hello'

Caveats

#1. Cross-stub uses ruby’s Marshal class to dump & load the stubs, thus it has the same limitations as Marshal

#2. Cross-stub only supports stubbing of class methods, since it makes no sense to do cross process stubbing of instances

TODO(s)

#1. We can possibly use Hijack (github.com/ileitch/hijack) within the current test process to trigger refreshing of stubs in the other process, thus using cross-stub no longer requires changing of any existing application code to insert CrossStub.refresh(…). This has in fact been our original intended strategy, however, we have not been able to do so as Hijack currently hangs on starting up on our development machines.

Contacts

Written 2009 by:

#1. NgTzeYang, contact ngty77gmail.com or github.com/ngty

#2. WongLiangZan, contact liangzangmail.com or github.com/liangzan

Released under the MIT license