我写了一个非常简单的日期服务器:
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
我真的很感激这方面的一些帮助。这只是一个简单的练习,我想看看如何最好地为这种服务器实现一些测试。比如,模拟用户连接并输入他们的名字。 提前谢谢。
答案 0 :(得分:2)
我会考虑将服务器组织为具有此签名的类:
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"时,服务器可以重新启动该框。不要让服务器直接执行此操作,而是让它调用" rebooter"宾语。在您的测试中,创建一个假的重启器并将其提供给服务器:
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