Today, I was writing some tests and I needed to mock a server. Now, normally for mock objects, I use the FlexMock library. But for this one, it had a LOT of different input parameters and I didn't want to specify all of them with a corresponding result. I really just wanted to record the way the server actually responds for the calls; save the responses; and play them back in a mock object. So, I wrote a module to do just that.
module VCR
module VCR::Parent
# Watch every public method in this class
# TODO: Question? Do I want to exclude Object's methods?
def watch_all_public_methods
o = Object.new
for m in public_methods - o.methods
unless ['record_method'].include?(m)
record_method(m)
end
end
end
end
#
# Creates a recording Module using the given filename.
#
def VCR::Record(filename)
Module.new do
extend_object(VCR::Parent)
@@recording_filename = filename
@@results = {}
#Watches a method and records the result.
def watch_method(symbol)
self.class.send(:define_method, symbol, Proc.new {|*args|
result = super
@@results[[symbol, *args]] = result
File.open(@@recording_filename, 'w') do |f|
Marshal.dump(@@results, f)
end
result
})
end
end
end
#
# Creates a playback Module given the filename for saved data.
#
def VCR::Playback(filename)
Module.new do
extend_object(VCR::Parent)
@@results = Marshal.load(File.open(filename))
#watches a method for playback
#when the given method is called, it will return the response
#from the saved file.
def watch_method(symbol)
self.class.send(:define_method, symbol, Proc.new {|*args|
@@results[[symbol, *args]]
})
end
end
end
end
So for example, Lets say I have a http server object that gets data from the internet.
class HttpServer
def get_data(url) ... end
end
I can create a new server that will mimic that class.
class VCRServer < HttpServer
include VCR::Record('save_filename.dat')
def initialize(*args)
super
watch_method :get_data
end
end
This will only record the method get_data. If we wanted to record everything, we
could have used:
watch_all_public_methods()
To swtich this Class to playback-mode, simple change 'Recorder' to 'Playback'
class VCRServer < HttpServer
include VCR::Playback('save_filename.dat')
def initialize(*args)
super
watch_method :get_data
end
end
Friday, July 13, 2007
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment