【问题标题】:How to test if some specific rack middleware is being used?如何测试是否正在使用某些特定的机架中间件?
【发布时间】:2015-01-12 21:06:21
【问题描述】:

更具体地说,我在这里谈论的是sentry-ravensinatra。我看到了测试sinatra 应用程序或中间件的示例。但是我没有看到有人测试是否存在某些特定的中间件。或者我应该测试行为,而不是配置(或者我应该如何称呼它)?

【问题讨论】:

    标签: ruby testing sinatra rack sentry


    【解决方案1】:

    重要的事情(我想说)是行为,但如果你想检查中间件,我建议在深入研究Sinatra source 之后有两种方法(可能有更简单/更好的方法):

    环境

    在 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 哈希中插入了一些东西,它只会向你显示中间件,例如

    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
    

    在模块化应用的类定义中调用它,你可以得到一个数组中的中间件:

    require 'sinatra/base'
    
    class AnExample < Sinatra::Base
      use MyBad
      warn "self.middleware = #{self.middleware}"
    

    输出:

    self.middleware = [[MyBad, [], nil]]
    

    可能有办法从 Sinatra::Application 获取它,但我没有看过。

    【讨论】:

    • 我没有坚持测试而不是行为。如果中间件以一种或另一种方式表现出来,您可以考虑使用它。此外,我从raven-ruby 人那里得到了an answer。不过我还没有检查。
    • @x-yuri 如果它以一种或另一种方式表现出来,那么它会影响行为,你可以检查一下。如果它不影响行为,那么问题出在哪里? “我没有坚持测试而不是行为。”我不知道这是什么意思。
    • If it manifests itself one way or the other then it will affect behaviour and you can check that. 所以我在问如何检查。不过,我可能还不够清楚。 I don't know what this means. 任何人向我展示如何在这里测试行为,而不是状态(或配置,或其他任何东西),我都很好。
    • @x-yuri 您链接到的问题线程中的last comment 很好,可能是a mock with should_receive
    • 如果您将此解决方案添加到您的答案中,我会接受它。
    【解决方案2】:

    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)
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-01
      • 2012-04-24
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 2011-12-04
      • 2021-03-21
      • 1970-01-01
      相关资源
      最近更新 更多