RSpec and ZeroMQ
December 19 2011 14:30 CET
When you have something like this using ZeroMQ:
client.rb
class Client
def self.listen
socket = ZMQ::Context.new.socket(ZMQ::UPSTREAM)
socket.bind("tcp://127.0.0.1:1234")
while(true)
msg = socket.recv()
if msg == "quit"
socket.close
return
end
...
end
And you would like to write a spec for it you will run into the problem that #recv() is a blocking method.
How best to go about this? I would prefer some kind of spawning a seperate process but that get’s kinda hairy.
Instead I have opted to simply mock it and write the following two methods:
spec_helper.rb
def queue_zmq_message(msg)
@zmq_queue ||= []
@zmq_queue << msg
end
def mock_zmq
@zmq_queue ||= []
zmq_socket = mock('zmq_socket')
zmq_socket.stub(:bind)
zmq_socket.stub(:recv).and_return do
queue_zmq_message("quit") if @zmq_queue.empty?
@zmq_queue.shift
end
zmq_context = mock('zmq_context')
zmq_context.stub(:socket).and_return(zmq_socket)
ZMQ::Context.stub(:new).and_return(zmq_context)
zmq_socket.stub(:close)
end
This allows me to do something like this in my specs:
client_spec.rb
before do
mock_zmq
end
it "should do something when a message is received" do
queue_zmq_message "some message"
# Expections here
Client.listen
# ...or expections here
end
This is a bit simplified from the project I am using it in now. But you should get the point. The program accepts some sort of quit signal as well to break us out of the main loop.