December 19 2011 14:30 CET
When you have something like this using ZeroMQ:
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:
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:
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.