如何测试是否正在使用某些特定的机架中间件?
How to test if some specific rack middleware is being used?
更具体地说,我在这里说的是sentry-raven
和sinatra
。我看到了测试 sinatra
应用程序或中间件的示例。但是我没有看到有人测试是否存在某些特定的中间件。或者我应该测试行为,而不是配置(或者我应该如何称呼它)?
重要的事情(我会说)是行为,但是如果你想检查中间件,我建议在深入研究 Sinatra source 之后有两种方法(可能有很多easier/better 种方式):
环境
在 Sinatra 源代码中 there's a method that uses the env to check if a middleware is already present:
# Behaves exactly like Rack::CommonLogger with the notable exception that it does nothing,
# if another CommonLogger is already in the middleware chain.
class CommonLogger < Rack::CommonLogger
def call(env)
env['sinatra.commonlogger'] ? @app.call(env) : super
end
您可以在路线中做同样的事情,例如
get "/env-keys" do
env.keys.inspect
end
如果它在 env hash 中插入了一些东西,它只会向你显示中间件,例如
class MyBad
def initialize app, options={}
@app = app
@options = options
end
def call env
@app.call env.merge("mybad" => "I'm sorry!")
end
end
输出:
["SERVER_SOFTWARE", "SERVER_NAME", "rack.input", "rack.version", "rack.errors", "rack.multithread", "rack.multiprocess", "rack.run_once", "REQUEST_METHOD", "REQUEST_PATH", "PATH_INFO", "REQUEST_URI", "HTTP_VERSION", "HTTP_HOST", "HTTP_CONNECTION", "HTTP_CACHE_CONTROL", "HTTP_ACCEPT", "HTTP_USER_AGENT", "HTTP_DNT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "GATEWAY_INTERFACE", "SERVER_PORT", "QUERY_STRING", "SERVER_PROTOCOL", "rack.url_scheme", "SCRIPT_NAME", "REMOTE_ADDR", "async.callback", "async.close", "rack.logger", "mybad", "rack.request.query_string", "rack.request.query_hash", "sinatra.route"]
它接近该列表的末尾。
中间件方法
There's also a method called middleware
in Sinatra::Base:
# Middleware used in this class and all superclasses.
def middleware
if superclass.respond_to?(:middleware)
superclass.middleware + @middleware
else
@middleware
end
end
在模块化应用程序的class定义中调用它,您可以获得数组中的中间件:
require 'sinatra/base'
class AnExample < Sinatra::Base
use MyBad
warn "self.middleware = #{self.middleware}"
输出:
self.middleware = [[MyBad, [], nil]]
可能有一种方法可以从Sinatra::Application获取它,但我没看过。
在 ruby-raven
guys 的帮助下,我们得到了这个:
ENV['RACK_ENV'] = 'test'
# the app: start
require 'sinatra'
require 'sentry-raven'
Raven.configure(true) do |config|
config.dsn = '...'
end
use Raven::Rack
get '/' do
'Hello, world!'
end
# the app: end
require 'rspec'
require 'rack/test'
Raven.configure do |config|
logger = ::Logger.new(STDOUT)
logger.level = ::Logger::WARN
config.logger = logger
end
describe 'app' do
include Rack::Test::Methods
def app
@app || Sinatra::Application
end
class TestRavenError < StandardError; end
it 'sends errors to sentry' do
@app = Class.new Sinatra::Application do
get '/' do
raise TestRavenError
end
end
allow(Raven.client).to receive(:send).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven.client).to have_received(:send)
end
end
或者如果 raven
发送请求妨碍了(当测试失败是因为 raven
发送请求,而不是因为潜在的错误),可以禁用它们:
Raven.configure(true) do |config|
config.should_send = Proc.new { false }
end
然后模拟 Raven.send_or_skip
:
...
allow(Raven).to receive(:send_or_skip).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven).to have_received(:send_or_skip)
...
更具体地说,我在这里说的是sentry-raven
和sinatra
。我看到了测试 sinatra
应用程序或中间件的示例。但是我没有看到有人测试是否存在某些特定的中间件。或者我应该测试行为,而不是配置(或者我应该如何称呼它)?
重要的事情(我会说)是行为,但是如果你想检查中间件,我建议在深入研究 Sinatra source 之后有两种方法(可能有很多easier/better 种方式):
环境
在 Sinatra 源代码中 there's a method that uses the env to check if a middleware is already present:
# Behaves exactly like Rack::CommonLogger with the notable exception that it does nothing,
# if another CommonLogger is already in the middleware chain.
class CommonLogger < Rack::CommonLogger
def call(env)
env['sinatra.commonlogger'] ? @app.call(env) : super
end
您可以在路线中做同样的事情,例如
get "/env-keys" do
env.keys.inspect
end
如果它在 env hash 中插入了一些东西,它只会向你显示中间件,例如
class MyBad
def initialize app, options={}
@app = app
@options = options
end
def call env
@app.call env.merge("mybad" => "I'm sorry!")
end
end
输出:
["SERVER_SOFTWARE", "SERVER_NAME", "rack.input", "rack.version", "rack.errors", "rack.multithread", "rack.multiprocess", "rack.run_once", "REQUEST_METHOD", "REQUEST_PATH", "PATH_INFO", "REQUEST_URI", "HTTP_VERSION", "HTTP_HOST", "HTTP_CONNECTION", "HTTP_CACHE_CONTROL", "HTTP_ACCEPT", "HTTP_USER_AGENT", "HTTP_DNT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "GATEWAY_INTERFACE", "SERVER_PORT", "QUERY_STRING", "SERVER_PROTOCOL", "rack.url_scheme", "SCRIPT_NAME", "REMOTE_ADDR", "async.callback", "async.close", "rack.logger", "mybad", "rack.request.query_string", "rack.request.query_hash", "sinatra.route"]
它接近该列表的末尾。
中间件方法
There's also a method called middleware
in Sinatra::Base:
# Middleware used in this class and all superclasses.
def middleware
if superclass.respond_to?(:middleware)
superclass.middleware + @middleware
else
@middleware
end
end
在模块化应用程序的class定义中调用它,您可以获得数组中的中间件:
require 'sinatra/base'
class AnExample < Sinatra::Base
use MyBad
warn "self.middleware = #{self.middleware}"
输出:
self.middleware = [[MyBad, [], nil]]
可能有一种方法可以从Sinatra::Application获取它,但我没看过。
在 ruby-raven
guys 的帮助下,我们得到了这个:
ENV['RACK_ENV'] = 'test'
# the app: start
require 'sinatra'
require 'sentry-raven'
Raven.configure(true) do |config|
config.dsn = '...'
end
use Raven::Rack
get '/' do
'Hello, world!'
end
# the app: end
require 'rspec'
require 'rack/test'
Raven.configure do |config|
logger = ::Logger.new(STDOUT)
logger.level = ::Logger::WARN
config.logger = logger
end
describe 'app' do
include Rack::Test::Methods
def app
@app || Sinatra::Application
end
class TestRavenError < StandardError; end
it 'sends errors to sentry' do
@app = Class.new Sinatra::Application do
get '/' do
raise TestRavenError
end
end
allow(Raven.client).to receive(:send).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven.client).to have_received(:send)
end
end
或者如果 raven
发送请求妨碍了(当测试失败是因为 raven
发送请求,而不是因为潜在的错误),可以禁用它们:
Raven.configure(true) do |config|
config.should_send = Proc.new { false }
end
然后模拟 Raven.send_or_skip
:
...
allow(Raven).to receive(:send_or_skip).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven).to have_received(:send_or_skip)
...