如何使用rspec测试multithreadingTCPServer

我写了一个非常简单的日期服务器:

require 'socket' s = TCPServer.new 3939 while (conn = s.accept) Thread.new(conn) do |c| c.print "Enter your name: " name = c.gets.chomp c.puts "Hi #{name}, the date is..." c.print `date` c.close end end 

用户连接,产生一个线程,他们输入他们的名字,返回日期。 简单。

我想知道如何在rspec中测试这样的东西。 我有过的一些想法:1。)使用VCR记录服务器连接,使用Timecop冻结并返回日期。 2.)在之前的块中连接到实际的服务器。 我不完全确定如何执行此操作,因为当我运行rspec时,我认为它实际上运行服务器…或者发生了一些事情,终端只是冻结并等待某些东西……示例测试代码:

 before @server = TCPSever.new 3939 end it "does something.." conn = @server.accept # etc end after @server.close end 

3.)存根连接。 4.)甚至不要尝试测试创建的线程,只需将名称请求和日期响应放入方法并测试它。

我查看了puma的测试,看看他们如何测试线程: https : //github.com/puma/puma/blob/master/test/test_puma_server.rb#L27

我真的很感激这方面的一些帮助。 这只是一个简单的练习,我想看看如何最好地为这种服务器实现一些测试。 比如,模拟用户连接并输入他们的名字。 先感谢您。

我会考虑将服务器组织为具有此签名的类:

 class DateServer # Initialize the server. If port is 0, find # an unused port and use that. def initialize(port = 0) def start def stop def port # return the bound port end 

然后你的测试设置并撕下服务器:

 before do @server = Server.new @server.start end after do @server.stop end 

由于这个服务器没有副作用,你的测试将连接到它,发送一些东西,并得到一些东西:

 it "prints the date" do @socket = TCPSocket.new("localhost", @server.port) @socket.puts "Fred" @socket.close_write output = @socket.read expect(output).to match /Hi Fred/ end 

要检查输出是否包含日期,请使用正则表达式。 这是一个未经测试的可能不正确的例子:

  expect(output).to match /\w+ \w+ +\d+ \d+:\d+:\d+ \w+ \d+/ 

或者使用例如timecop gem,以便测试可以强制时间,然后检查日期的完全匹配。

这个服务器没有副作用,但如果确实如此,我会把副作用放在他们自己的对象中。 假设服务器可以在用户名为“Barney”时重新启动该框。 不要让服务器直接执行此操作,而是让它调用“rebo​​oter”对象。 在您的测试中,创建一个假的重启器并将其提供给服务器:

 before do @rebooter = double(Rebooter) @server = Server.new(rebooter: @rebooter) @server.start end 

然后:

 "it should reboot when Barney connects" do @rebooter.should_receive(:reboot) @socket = TCPSocket.new("localhost", @server.port) @socket.puts "Barney" @socket.close_write output = @socket.read end