代码之家  ›  专栏  ›  技术社区  ›  Brian

使用rack::test和sinatra测试控制器实例变量

  •  8
  • Brian  · 技术社区  · 15 年前

    我有一个Sinatra应用程序,它提供只读或可编辑的页面,具体取决于用户是否登录。

    控制器设置变量 @can_edit ,用于视图隐藏/显示编辑链接。我如何测试 @加拿大编辑 在我的测试中的值?我不知道如何在rack::test下获取控制器的当前实例。

    我用 class_eval 存根 logged_in? 方法在控制器中,但我不得不求助于检查 last_response.body 以查看我的编辑链接 @加拿大编辑 是否已设置。

    我如何测试 @可以编辑 直接?

    3 回复  |  直到 8 年前
        1
  •  8
  •   Alex Reisner    15 年前

    不幸的是,我认为不修改rack::test是不可能的。当您在应用程序测试期间提出请求时,rack::test会执行以下操作:

    1. 将请求添加到最近请求的列表中
    2. 创建应用程序的新实例并调用其 call 方法
    3. 将应用程序的响应添加到最近响应的列表中

    很容易访问 last_request last_response 但不幸的是,在应用程序运行时没有保存有关其状态的信息。

    如果您有兴趣将一个rack::test补丁一起进行黑客攻击,请从 rack-test/lib/rack/mock_session.rb 在第30行。这是rack::test运行应用程序并接收标准rack app返回值(status、headers、body)的地方。我猜您还需要修改应用程序,以收集和访问它的所有实例变量。

    在任何情况下,最好测试结果,而不是实现细节。如果要确保编辑链接不可见,请按dom id测试编辑链接是否存在:

    assert last_response.body.match(/<a href="..." id="...">/)
    
        2
  •  4
  •   Shuhei Kagawa    13 年前

    一点小技巧是可能的。Sinatra应用程序的实例不可用,因为它们是在调用Sinatra::Base Call时创建的。亚历克斯解释说。这个黑客在前面准备了一个实例,让下一个调用获取它。

    require 'something/to/be/required'
    
    class Sinatra::Base
      @@prepared = nil
    
      def self.onion_core
        onion = prototype
        loop do
          onion = onion.instance_variable_get('@app')
          return onion if onion.class == self || onion.nil?
        end
      end
    
      def self.prepare_instance
        @@prepared = onion_core
      end
    
      # Override
      def call(env)
        d = @@prepared || dup
        @@prepared = nil
        d.call!(env)
      end
    end
    
    describe 'An Sinatra app' do
      include Rack::Test::Methods
    
      def app
        Sinatra::Application
      end
    
      it 'prepares an app instance on ahead' do
        app_instance = app.prepare_instance    
        get '/foo'
        app_instance.instance_variable_get('@can_edit').should be_true
      end
    end
    

    我想出了这个方法 mock the instance that runs the current test 首先。

        3
  •  0
  •   random-forest-cat    8 年前

    这是一个讨厌但可行的选择

    # app.rb - sets an instance variable for all routes
    before do
      @foo = 'bar'
    end
    
    # spec.rb
    it 'sets an instance variable via before filter' do
      my_app = MySinatraApplication
      expected_value = nil
      # define a fake route
      my_app.get '/before-filter-test' do
        # as previously stated, Sinatra app instance isn't avaiable until #call is performed
        expected_value = @foo
      end
      my_app.new.call({
        'REQUEST_METHOD' => 'GET',
        'PATH_INFO' => '/before-filter-test',
        'rack.input' => StringIO.new
      })
      expect(expected_value).to eq('bar')
    end
    

    这允许您在筛选和/或访问为基本应用程序创建的实例变量之前对Sinatra进行测试。