【发布时间】:2017-09-08 10:22:02
【问题描述】:
我想获取 rack-test 正在测试的应用程序实例,以便我可以模拟它的一些方法。我以为我可以简单地将应用程序实例保存在 app 方法中,但由于某些奇怪的原因,它不起作用。似乎rack-test 只是使用实例来获取类,然后创建自己的实例。
我做了一个测试来证明我的问题(它需要运行 gems“sinatra”、“rack-test”和“rr”):
require "sinatra"
require "minitest/spec"
require "minitest/autorun"
require "rack/test"
require "rr"
describe "instantiated app" do
include Rack::Test::Methods
def app
cls = Class.new(Sinatra::Base) do
get "/foo" do
$instance_id = self.object_id
generate_response
end
def generate_response
[200, {"Content-Type" => "text/plain"}, "I am a response"]
end
end
# Instantiate the actual class, and not a wrapped class made by Sinatra
@app = cls.new!
return @app
end
it "should have the same object id inside response handlers" do
get "/foo"
assert_equal $instance_id, @app.object_id,
"Expected object IDs to be the same"
end
it "should trigger mocked instance methods" do
mock(@app).generate_response {
[200, {"Content-Type" => "text/plain"}, "I am MOCKED"]
}
get "/foo"
assert_equal "I am MOCKED", last_response.body
end
end
rack-test 怎么没有使用我提供的实例?如何获取rack-test 正在使用的实例,以便模拟generate_response 方法?
更新
我没有取得任何进展。。事实证明,rack-test 在发出第一个请求时会即时创建测试实例(即get("/foo")),因此在此之前无法模拟应用程序实例。
我已经用rr的stub.proxy(...)拦截了.new、.new!和.allocate;并添加了带有实例类名和object_id 的 puts 语句。我还在被测类的构造函数和请求处理程序中添加了这样的语句。
这是输出:
来自构造函数:注意对象 ID。测试实例(从请求处理程序打印)从未经过.new 并且从未初始化。
因此,令人困惑的是,被测试的实例从未被创建,但不知何故仍然存在。我的猜测是 allocate 正在被使用,但代理拦截显示它没有。我自己运行TestSubject.allocate 来验证拦截是否有效,并且确实有效。
我还在测试类中添加了inherited、included、extended 和prepended 挂钩并添加了打印语句,但它们从未被调用。这让我完全不知道在引擎盖下进行了什么样的可怕的黑魔法机架测试。
总结一下:测试实例是在发送第一个请求时动态创建的。被测试的实例是由邪能魔法创建的,并且躲过了所有用钩子抓住它的尝试,所以我找不到模拟它的方法。几乎感觉rake-test 的作者已经竭尽全力确保在测试期间不会触及应用实例。
我还在摸索解决办法。
【问题讨论】:
-
您可以使用 let 辅助方法来记忆应用程序。在此处阅读更多信息relishapp.com/rspec/rspec-core/v/2-5/docs/helper-methods/…
标签: ruby unit-testing rack rack-test