从TestCase调用Sinatra应用程序实例方法

fgu*_*len 13 ruby rack sinatra

我在一个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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

mat*_*att 18

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

def app
  MyApp.new!
end
Run Code Online (Sandbox Code Playgroud)

当然我只注意到我提出以下内容后,我将留下,因为它可能是有用的/提供信息.


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

def app
  a = MyApp.allocate
  a.send :initialize
  a
end
Run Code Online (Sandbox Code Playgroud)

这有点像黑客,但它可能对测试很有用.

另一种技术是"走"中间件堆栈直到你上课.以下是一个有点脆弱,因为它依赖于所有涉及使用该名称@app来引用堆栈中的下一个应用程序的中间件,但这是相当常见的.

def app
  a = MyApp.new
  while a.class != MyApp
    a = a.instance_variable_get(:@app)
  end
  a
end
Run Code Online (Sandbox Code Playgroud)

这不会对尚未发布的Sinatra 1.4起作用(至少不会在当前的主机上提交41840746e866e8e8e9a0eaafc53d8b9fe6615b12),因为new现在返回一个Wrapper并且循环永远不会结束.在这种情况下,您可以直接从@instance变量中获取基类:

def app
  MyApp.new.instance_variable_get :@instance
end
Run Code Online (Sandbox Code Playgroud)

(注意最后一种技术可能会在最终的1.4发布之前发生变化).