配置 rack-test 以间接启动服务器

Configuring rack-test to start the server indirectly

这是我的机架应用程序:

class MainAppLogic
    def initialize
        Rack::Server.start(:app =>Server, :server => "WEBrick", :Port => "8080")
    end
end

class Server
    def self.call(env)
        return [200, {},["Hello, World"]]
    end
end

实际上 运行 时,它会按应有的方式行事,并且 returns "Hello World" 对所有请求。我无法说服 rack-test 使用它。这是我的测试:

require "rspec"
require "rack/test"
require "app"

# Rspec config source: https://github.com/shiroyasha/sinatra_rspec    
RSpec.configure do |config|
    config.include Rack::Test::Methods
end

describe MainAppLogic do

    # App method source: https://github.com/shiroyasha/sinatra_rspec
    def app
        MainAppLogic.new
    end

    it "starts a server when initialized" do
        get "/", {}, "SERVER_PORT" => "8080"
        last_response.body.should be != nil
    end
end

当我测试这个时,它没有抱怨 MainAppLogic 不是机架服务器,具体来说,它没有响应 MainAppLogic.call。我怎样才能让它知道忽略 MainAppLogic 不是机架服务器而只向 localhost:8080 发出请求,因为那里的服务器已经启动?

您的应用应该是 class 名称,例如代替:

def app
  MainAppLogic.new
end

你必须使用

def app
  MainAppLogic
end

您不需要为 get 指定端口,因为机架应用程序在测试上下文中运行;所以这应该是正确的方式:

it "starts a server when initialized" do
    get "/"
    last_response.body.should be != nil
end

此外,作为建议,更喜欢使用新的 expect 格式而不是 should,请参阅 http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/

你的 MainAppLogic 应该是这样的:

class MainAppLogic < Sinatra::Base
  get '/' do
    'Hello world'
  end
end

第一件事:为什么自定义 class 到 运行 应用程序?您可以使用 rackup 工具,这是 运行ning Rack 应用程序的实际标准。关于它的更多细节 here.

您的应用程序代码将变为:

class App
  def call(env)
    return [200, {}, ['Hello, World!']]
  end
end

并与 config.ru

require_relative 'app'

run App.new

您可以通过 运行ning rackup 在您的项目目录中启动该应用程序。

至于错误,消息已经很清楚了。 rack-test 期望 app 方法的 return 值将是机架应用程序的实例(响应 call 方法的对象)。看看 rack-test 内部发生了什么(很容易理解,作为提示——按给定的顺序关注这些:lib/rack/test/methods.rb#L30 lib/rack/mock_session.rb#L7 lib/rack/test.rb#L244 lib/rack/mock_session.rb#L30 . 注意 Rack::MockSession 是如何实例化的,在处理请求时如何使用它(例如,当您在测试中调用 get 方法时)以及最后如何在您的应用程序上执行 call 方法。

我希望现在清楚为什么测试应该看起来更像这样(是的,执行测试时不需要服务器 运行ning):

describe App do
  def app
    App.new
  end

  it "does a triple backflip" do
    get "/"
    expect(last_response.body).to eq("Hello, World")
  end
end

P.S。 抱歉链接到 rack-test 的形式,我目前的点数不能添加超过 2 个 :P