ruby - 连接到后台 EventMachine 应用程序以进行单元测试

标签 ruby macos sockets eventmachine

我正在使用 EventMachine 编写 headless Ruby 应用程序通过套接字进行通信。我想为这个应用程序编写一些单元测试。这意味着我的 Ruby 测试脚本需要在后台启动该应用程序,与其执行套接字通信,然后关闭该进程。

此代码失败。套接字连接被拒绝。

require 'socket'
PORT = 7331
CMD = File.expand_path("../../bin/rb3jay",__FILE__)
@thread = Thread.new{ `#{CMD} -D --port #{PORT}` }
@socket = TCPSocket.open('localhost', PORT)
#=> Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 7331

如果我在尝试套接字连接之前注入(inject) 2 秒的延迟,它会按预期工作:

@thread = Thread.new{ `#{CMD} -D --port #{PORT}` }
sleep 2
@socket = TCPSocket.open('localhost', PORT)

这似乎是一个严重的黑客行为。也许 2 秒对我的机器来说足够长,但在其他地方太短了。

我应该如何在后台正确启动我的 EventMachine 应用程序,并在它准备好后立即创建一个套接字连接?

最佳答案

不确定是否有更好的方法,但我使用retry 解决了这个问题:

@thread = Thread.new{ `#{CMD} -D --port #{PORT}` }
begin
  @socket = TCPSocket.open('localhost', PORT)
rescue Errno::ECONNREFUSED
  sleep 0.1
  retry
end

这将无限期地每秒尝试建立连接 10 次,直到成功为止。一个更强大的解决方案可能是使用计数器或计时器最终放弃,以防出现严重错误。

完整的测试代码如下所示:

require 'socket'
require 'minitest/autorun'

PORT = 7331
CMD = File.expand_path("../../bin/rb3jay",__FILE__)

class TestServer < MiniTest::Unit::TestCase
  def setup
    @pid = Process.spawn "#{CMD} -D --port #{PORT}"
    begin
      @socket = TCPSocket.open('localhost', PORT)
    rescue Errno::ECONNREFUSED
      sleep 0.1
      retry
    end
  end

  def teardown
    if @socket && !@socket.closed?
      @socket.puts("quit") # try for a nice shutdown
      @socket.close
    end
    Process.kill("HUP",@pid)
  end

  def test_aaa
    # my test code
  end

  def test_bbb
    # more test code
  end
end

关于ruby - 连接到后台 EventMachine 应用程序以进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31758247/

相关文章:

ruby - 在 Ruby 中,如何读取放置在程序/脚本本身中的数据?

ruby-on-rails - 任何调试 RSpec 请求规范的方法?

objective-c - Cocoa:当窗口不可见时应用程序关闭

c++ - 如何通过 C++ 在 Mac OS 中运行外部程序?

c# - Windows Service通信,套接字,C#

windows - 在 Windows 上使用套接字

java - 通过 HTTP 建立 RMI 隧道的最佳方式

ruby - Sinatra 模板中的 If 语句

objective-c - Mac OS X 应用程序的最小窗口大小

javascript - JavaScript 中的 Rails 哈希,访问值