只需编写一个小装饰器来处理服务器的显式和隐式启动,并允许您确定服务器是否已启动。
想象这是需要启动的真实服务器:
class TheActualServer
def initialize
puts 'Server starting'
end
def operation1
1
end
def operation2
2
end
def kill
puts 'Server stopped'
end
end
可重用的装饰器可能如下所示:
class ServiceWrapper < BasicObject
def initialize(&start_procedure)
@start_procedure = start_procedure
end
def started?
!!@instance
end
def instance
@instance ||= @start_procedure.call
end
alias start instance
private
def method_missing(method_name, *arguments)
instance.public_send(method_name, *arguments)
end
def respond_to?(method_name)
super || instance.respond_to?(method_name)
end
end
现在您可以在您的规范中应用它,如下所示:
describe 'something' do
let(:server) do
ServiceWrapper.new { TheActualServer.new }
end
specify { expect(server.operation1).to eql 1 }
specify { expect(server.operation2).to eql 2 }
specify { expect(123).to be_a Numeric }
context 'when server is running' do
before(:each) { server.start }
specify { expect('abc').to be_a String }
specify { expect(/abc/).to be_a Regexp }
end
after(:each) { server.kill if server.started? }
end
当在装饰器上调用方法时,如果存在,它将运行自己的实现。例如,如果#started?
被调用,它将回答实际服务器是否已启动。如果它没有该方法的自己的实现,它会将方法调用委托给由该方法返回的服务器对象。如果此时它没有对实际服务器实例的引用,它将运行提供start_procedure
的以获取一个并记住它以供将来调用。
如果您将所有发布的代码放入一个名为的文件server_spec.rb
中,则可以使用以下命令运行它:
rspec server_spec.rb
输出将是这样的:
something
Server starting
Server stopped
should eql 1
Server starting
Server stopped
should eql 2
should be a kind of Numeric
when server is running
Server starting
Server stopped
should be a kind of String
Server starting
Server stopped
should be a kind of Regexp
Finished in 0.00165 seconds (files took 0.07534 seconds to load)
5 examples, 0 failures
请注意,在示例 1 和 2 中,调用了服务器上的方法,因此您会看到由装饰器隐式启动的服务器输出。
在示例 3 中,根本没有与服务器交互,因此您在日志中看不到服务器的输出。
然后在示例 4 和 5 中,示例代码中没有与服务器对象直接交互,而是通过一个 before 块显式启动服务器,这在输出中也可以看到。