首先,您的测试实际上不会通过,因为错误没有传递给测试。它只在服务器端提出。幸运的是, rack-test 提供了last_response.errors
检查是否有错误的方法。因此,我将按如下方式编写上述测试:
def test_rack_timeout_should_throw_timed_out_exception
Rack::Timeout.stubs(:timeout).returns(0.0001)
get '/dosomething'
assert last_response.server_error?, 'There was no server error'
assert last_response.errors.include?('Timeout::Error'), 'No Timeout::Error raised'
Rack::Timeout.unstub
end
现在唯一要做的就是通过覆盖路由来模拟缓慢的响应。起初看起来很简单,但当我拿到它时,我意识到这根本不是那么简单。我摆弄了很多,并在这里想出了这个:
class Sinatra::Base
def self.with_fake_route method, route, body
old_routes = routes.dup
routes.clear
self.send(method.to_sym, route.to_s, &body.to_proc)
yield
routes.merge! old_routes
end
end
它将允许您在传递给该方法的块内临时仅使用一条路线。例如,现在您可以通过以下方式模拟慢速响应:
MyModule::MySinatra.with_fake_route(:get, '/dosomething', ->{ sleep 0.0002 }) do
get '/dosomething'
end
请注意,get '/dosomething'
块内部不是临时路由的定义,而是机架测试触发模拟请求的方法。实际的覆盖路由以 的参数形式指定with_route
。
这是我能想到的最好的解决方案,但我希望看到一种更优雅的方式来解决这个问题。
完整的工作示例(在 Ruby 1.9.3.p385 上运行):
require 'sinatra/base'
require 'rack/timeout'
module MyModule
class MySinatra < Sinatra::Base
use Rack::Timeout
Rack::Timeout.timeout = 10
get '/dosomething' do
'foo'
end
end
end
require 'test/unit'
require 'rack/test'
require 'mocha/setup'
class Sinatra::Base
def self.with_fake_route method, route, body
old_routes = routes.dup
routes.clear
self.send(method.to_sym, route, &body)
yield
routes.merge! old_routes
end
end
class Tests < Test::Unit::TestCase
include Rack::Test::Methods
def app
MyModule::MySinatra
end
def test_rack_timeout_should_throw_timed_out_exception
Rack::Timeout.stubs(:timeout).returns(0.0001)
MyModule::MySinatra.with_fake_route(:get, '/dosomething', ->{ sleep 0.0002 }) do
get '/dosomething'
end
assert last_response.server_error?, 'There was no server error'
assert last_response.errors.include?('Timeout::Error'), 'No Timeout::Error raised'
Rack::Timeout.unstub
end
end
产生:
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips