我在 Sinatra 应用程序中有一个util方法,我想从我的TestCase
进行测试。
问题是我不知道如何调用它,如果我只是使用app.util_method
我有错误NameError: undefined local variable or method 'util_method' for #<Sinatra::ExtendedRack:0x007fc0c43305b8>
class MyApp < Sinatra::Base
# [...] routes methods
# utils methods
def util_method
return "hi"
end
end
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
答案 0 :(得分:18)
Sinatra aliases the new
method to new!
在重新定义之前,所以最简单的解决方案是使用它:
def app
MyApp.new!
end
当然我只注意到之后我想出了以下内容,我将留下来,因为它可能有用/提供信息。
绕过Sinatra redefining the new
method and returning a complete Rack app获取实际基类的实例的一种可能方法是执行“真正的”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不起作用(至少不是当前的主人,commit 41840746e866e8e8e9a0eaafc53d8b9fe6615b12),因为new
现在返回Wrapper
class并且循环永远不会结束。在这种情况下,您可以直接从@instance
变量中获取基类:
def app
MyApp.new.instance_variable_get :@instance
end
(注意最后一种技术可能会在最终的1.4发布之前发生变化)。
答案 1 :(得分:3)
您遇到的问题是,MyApp.new不会返回MyApp的实例,而是包含App的中间件实例(通常是Rack :: Head或Sinatra :: ShowExceptions)。可以在帖子Sinatra Usage Question / Rack App中找到一个很好的解释。
我能想到的唯一解决方案是将实例方法更改为可以在没有实例本身的情况下调用的类方法。由于您的应用程序实例可能会针对每个请求进行新实例化,因此实例方法可能与您的方案中的类方法相比没有太多优势。
修改强>
在即将推出的Sinatra 1.4中,初始化将会改变。 Sinatra :: Base.new将返回一个Sinatra :: Wrapper实例,它暴露了#settings和#helpers。这可能有助于解决访问Sinatra :: Base实例方法的问题。有关详细信息,请参阅Sinatra Changelog。