13

我在Sinatra应用程序中有一个 util 方法,我想从我的TestCase.

问题是我不知道如何调用它,如果我只是使用app.util_method我有错误NameError: undefined local variable or method 'util_method' for #<Sinatra::ExtendedRack:0x007fc0c43305b8>

my_app.rb:

class MyApp < Sinatra::Base
  # [...] routes methods

  # utils methods
  def util_method
    return "hi"
  end
end

my_app_test.rb:

require "my_app.rb"
require "test/unit"
require "rack/test"

class MyAppTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    MyApp.new
  end

  # [...] routes methods tests

  def test_util_method
    assert_equal( "hi", app.util_method )
  end
end
4

2 回答 2

21

Sinatra在重新定义之前将方法别名为newnew!,因此最简单的解决方案是使用它:

def app
  MyApp.new!
end

当然,我只是注意到,我提出以下内容之后,我会留下来,因为它可能有用/信息丰富。


绕过 Sinatra 的一种可能的方法是重新定义new方法并返回一个完整的 Rack 应用程序,获取一个实例,你的实际基类是做“真实”new方法自己做的事情:

def app
  a = MyApp.allocate
  a.send :initialize
  a
end

这有点小技巧,但它可能对测试有用。

另一种技术是“遍历”中间件堆栈,直到您进入课堂。以下内容有点脆弱,因为它依赖于所有涉及的中间件来使用该名称@app来引用堆栈中的下一个应用程序,但这很常见。

def app
  a = MyApp.new
  while a.class != MyApp
    a = a.instance_variable_get(:@app)
  end
  a
end

不过,这不适用于尚未发布的 Sinatra 1.4(至少不适用于当前的 master,即commit 41840746e866e8e8e9a0eaafc53d8b9fe6615b12),因为new现在返回一个Wrapper并且循环永远不会结束。在这种情况下,您可以直接从@instance变量中获取基类:

def app
  MyApp.new.instance_variable_get :@instance
end

(请注意,最后一种技术可能会在最终的 1.4 版本之前发生变化)。

于 2012-08-22T22:44:13.030 回答
3

您遇到的问题是,MyApp.new 不返回 MyApp 的实例,而是包装您的应用程序的中间件实例(通常是 Rack::Head 或 Sinatra::ShowExceptions)。可以在线程Sinatra 使用问题/机架应用程序中找到一个很好的解释。

我能想到的唯一解决方案是将您的实例方法更改为可以在没有实例本身的情况下调用的类方法。由于您的应用程序的实例可能会为每个请求重新实例化,因此在您的场景中,实例方法可能与类方法相比没有太多优势。

编辑:

在即将到来的 Sinatra 1.4 中,初始化将会改变。Sinatra::Base.new 将返回一个 Sinatra::Wrapper 实例,它公开了#settings 和#helpers。这可能有助于解决访问 Sinatra::Base 实例方法的问题。有关更多信息,请参阅Sinatra 变更日志

于 2012-08-22T16:27:44.567 回答