这是我认为很简单但我在测试机架超时宝石时遇到的问题。我有一个sinatra基类,其端点有一些逻辑。
module MyModule
class MySinatra < Sinatra::Base
use Rack::Timeout
Rack::Timeout.timeout = 10
get '/dosomething' do
#do the normal logic.
end
end
end
有关rack-timeout gem的更多信息是here。我正在尝试设置一个测试,我可以发送一个请求,我知道这个请求会花费几秒钟才会失败。
这是迄今为止的测试
require "test/unit"
require "mocha/setup"
require 'rack/timeout'
def test_rack_timeout_should_throw_timed_out_exception_test
Rack::Timeout.stubs(:timeout).returns(0.0001)
assert_raises TimeoutError do
get "/dosomething"
end
Rack::Timeout.unstub
end
有很多方法可以做到,但我不确定它们将如何实施
对此的任何想法都将非常感激。
答案 0 :(得分:1)
首先,您的测试实际上不会通过,因为错误未传递给测试。它只在服务器端引发。幸运的是,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