8

我有一个 Sinatra 应用程序,根据用户是否登录,该应用程序将页面提供为只读或可编辑的。

控制器设置一个变量@can_edit,视图使用它来隐藏/显示编辑链接。如何@can_edit在我的测试中 test 的值?我不知道如何在 Rack::Test 下获取控制器的当前实例。

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

如何@can_edit直接测试的值?

4

3 回答 3

8

不幸的是,如果不修改 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 应用程序返回值(状态、标题、正文)。我的猜测是,您还必须修改您的应用程序,以收集并使其所有实例变量都可以访问。

无论如何,最好测试结果,而不是实现细节。如果要确保编辑链接不可见,请通过 DOM id 测试编辑链接是否存在:

assert last_response.body.match(/<a href="..." id="...">/)
于 2009-12-18T16:38:11.820 回答
4

有一点点破解是可能的。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

我首先想出了这种技术来模拟运行当前测试的实例

于 2011-12-27T12:08:30.683 回答
0

这是一个令人讨厌但可行的替代方案

# 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 进行测试。

于 2016-02-24T21:36:14.817 回答