= 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 another process, 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 using selenium, culerity, steam, blah, blah driver? 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. Rails: $ ./script/generate cucumber $ ./script/generate cross_stub === #2. Others (back to basics): # In the test setup method: CrossStub.setup :file => # 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 => For a full list of available cache stores, scroll down to take a look at the 'Cache Stores' section. == Using It Cross-stubbing is simple: === #1. Simple returning of nil or non-nil value: ==== #1.1. Class method: class Someone def self.say 'hello' end end Someone.xstub(:say) Someone.say # yields: nil Someone.xstub(:say => 'HELLO') Someone.say # yields: 'HELLO' ==== #1.2. Instance method: Someone.xstub(:say, :instance => true) Someone.new.say # yields: nil Someone.xstub({:say => 'HELLO'}, :instance => true) Someone.new.say # yields: 'HELLO' === #2. If a stubbed method requires argument, pass xstub a proc: ==== #2.1. Class method: Someone.xstub do def say(something) 'saying "%s"' % something end end Someone.say('HELLO') # yields: 'saying "HELLO"' ==== #2.2. Instance method: Someone.xstub(:instance => true) do def say(something) 'saying "%s"' % something end end Someone.new.say('HELLO') # yields: 'saying "HELLO"' IMPORTANT: Since switching from ParseTree to RubyParser, dynamic code analysis is no longer possible. When defining methods in the proc, fanciful coding is strongly discouraged, pls follow the conservative style suggested above. === #3. Something more complicated: something = 'hello' Someone.xstub do def say 'saying "%s"' % something end end Someone.say # failure !! The above fails as a result of undefined variable/method 'something', to workaround we can have: Someone.xstub(:something => 'HELLO') do def say 'saying "%s"' % something end end Someone.say # yields: 'saying "HELLO"' == Cache Stores Cache stores are needed to allow stubs to be made available for different processes. The following describes all cache stores available: === #1. File # Setting up (current process) CrossStub.setup :file => '' # Refreshing (other process) CrossStub.refresh :file => '' === #2. Memcache (requires memcache-client gem) # Setting up (current process) CrossStub.setup :memcache => 'localhost:11211/' # Refreshing (other process) CrossStub.refresh :memcache => 'localhost:11211/' === #3. Redis (requires redis gem) # Setting up (current process) CrossStub.setup :redis => 'localhost:6379/' # Refreshing (other process) CrossStub.refresh :redis => 'localhost:6379/' Adding new store is super easy (w.r.t testing & actual implementation), let me know if u need more :] == Caveats #1. Cross-stub uses ruby's Marshal class to dump & load the stubs, thus it has the same limitations as Marshal #2. Having switched from ParseTree to RubyParser, dynamic code analysis is no longer available, the proc taken by xstub no longer supports fanciful coding, pls follow the conservative style suggested in this README. == TODO(s) #1. We can possibly use Hijack (http://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 since 2009 by: #1. NgTzeYang, contact ngty77[at]gmail[dot]com or http://github.com/ngty #2. WongLiangZan, contact liangzan[at]gmail[dot]com or http://github.com/liangzan Released under the MIT license