【问题标题】:Configuring rack-test to start the server indirectly配置 rack-test 以间接启动服务器
【发布时间】:2016-08-18 12:04:35
【问题描述】:

这是我的机架应用程序:

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

当实际运行时,它会按照应有的方式运行并向所有请求返回“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 发出请求,因为那里的服务器已经启动?

【问题讨论】:

  • 这个建议不能帮助您解决问题,但您可能想知道标准的 Ruby 缩进是两个空格。缩进四还不错——Ruby 本身并不在意——只是看起来有点奇怪。

标签: ruby rspec rack-test


【解决方案1】:

第一件事:为什么要使用自定义类来运行应用程序?您可以使用rackup 工具,这是运行 Rack 应用程序的事实标准。更多细节here

然后您的应用代码变为:

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

config.ru

require_relative 'app'

run App.new

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

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

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

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

附: 对不起rack-test的链接形式,我目前的积分不能超过2个:P

【讨论】:

  • 非常感谢您的回答!在我重构整个项目之前,我认为它是无用的,现在这是我解决问题的参考。我看到您对 Stack Overflow 还很陌生,所以欢迎您!继续写出精彩的答案!
  • 不客气!而且我已经有一段时间了,只是没有写答案;)
【解决方案2】:

您的应用应该是类名,例如,而不是:

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

【讨论】:

  • 我没有使用 sinatra,所以最后一点无关紧要。我会在我的问题中澄清这一点
  • 另外,您的解决方案实际上并不适合我。 rspec 仍然像以前一样抱怨。
  • 即使你不使用 Sinatra,你仍然需要返回类名,而不是那个类的实例
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 2013-05-31
  • 2014-11-13
  • 2018-04-14
相关资源
最近更新 更多