使用 Rack::Test 测试 Sinatra

以下所有示例都假设使用 Test::Unit,以尽可能通用。有关在其他测试环境中使用测试助手的更多信息,请参阅 测试框架示例。要使用 Rack::Test 库(在您需要 rack/test 时使用),您需要安装 rack-test gem

gem install rack-test

您也可以将其添加到应用程序的 Gemfile 中,如下所示

gem 'rack-test'

示例应用程序:hello_world.rb

以下示例应用程序用于说明测试功能。假设它位于名为 hello_world.rb 的文件中

require 'sinatra'

get '/' do
  "Hello World #{params[:name]}".strip
end

使用 Rack::Test::Methods Mixin

Rack::Test::Methods 模块包含各种辅助方法,用于模拟对应用程序的请求并断言对响应的期望。它通常直接包含在测试上下文中,并提供一些辅助方法和属性。

以下是一个简单的示例,确保 hello world 应用程序正常运行

ENV['APP_ENV'] = 'test'

require 'hello_world'
require 'test/unit'
require 'rack/test'

class HelloWorldTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  def test_it_says_hello_world
    get '/'
    assert last_response.ok?
    assert_equal 'Hello World', last_response.body
  end

  def test_it_says_hello_to_a_person
    get '/', :name => 'Simon'
    assert last_response.body.include?('Simon')
  end
end

不使用 Mixin 使用 Rack::Test

由于各种原因,您可能不想将 Rack::Test::Methods 包含到您自己的类中。 Rack::Test 也支持这种测试风格,以下是上面示例中不使用 Mixin 的情况。

ENV['APP_ENV'] = 'test'

require 'hello_world'
require 'test/unit'
require 'rack/test'

class HelloWorldTest < Test::Unit::TestCase

  def test_it_says_hello_world
    browser = Rack::Test::Session.new(Rack::MockSession.new(Sinatra::Application))
    browser.get '/'
    assert browser.last_response.ok?
    assert_equal 'Hello World', browser.last_response.body
  end

  def test_it_says_hello_to_a_person
    browser = Rack::Test::Session.new(Rack::MockSession.new(Sinatra::Application))
    browser.get '/', :name => 'Simon'
    assert browser.last_response.body.include?('Simon')
  end
end

Rack::Test 的模拟请求方法

getputpostdeletehead 方法模拟了应用程序上相应的请求类型。测试通常从调用其中一个方法开始,然后对生成的响应进行一个或多个断言。

所有模拟请求方法都具有相同的参数签名

get '/path', params={}, rack_env={}
  • /path 是请求路径,可以选择包含查询字符串。

  • params 是一个包含查询/POST 参数的哈希表,一个字符串请求体,或者 nil

  • rack_env 是一个包含 Rack 环境值的哈希表。它可以用来设置请求头和其他与请求相关的信息,例如会话数据。有关可能键/值对的更多信息,请参阅 Rack SPEC

断言对响应的期望

一旦请求方法被调用,以下属性可用于进行断言

  • app - 处理模拟请求的 Sinatra 应用程序类。

  • last_request - 用于生成请求的 Rack::MockRequest

  • last_response - 一个 Rack::MockResponse 实例,包含有关应用程序生成的响应的信息。

断言通常针对 last_response 对象进行。请考虑以下示例

def test_it_says_hello_world
  get '/'
  assert last_response.ok?
  assert_equal 'Hello World'.length.to_s, last_response.headers['Content-Length']
  assert_equal 'Hello World', last_response.body
end

可选测试设置

Rack::Test 模拟请求方法将请求发送到名为 app 的方法的返回值。

如果您正在测试具有多个 Sinatra::Base 子类的模块化应用程序,只需将 app 方法设置为返回您的特定类。

  def app
    MySinatraApp
  end

如果您使用的是经典风格的 Sinatra 应用程序,那么您需要返回一个 Sinatra::Application 实例。

  def app
    Sinatra::Application
  end

使 Rack::Test 可用于所有测试用例

如果您希望 Rack::Test 方法在无需每次都包含的情况下可用于所有测试用例,您可以在 Test::Unit::TestCase 类中包含 Rack::Test 模块

require 'test/unit'
require 'rack/test'

class Test::Unit::TestCase
  include Rack::Test::Methods
end

现在,所有 TestCase 子类将自动拥有可用的 Rack::Test

测试框架示例

从版本 0.9.1 开始,Sinatra 不再提供特定于测试框架的帮助程序。在 sinatra/test/*.rb 中找到的那些已弃用,并在 Sinatra 1.0 中被删除。

RSpec

Sinatra 可以使用纯 RSpec 进行测试。 Rack::Test 模块应该包含在 describe 块中

ENV['APP_ENV'] = 'test'

require 'hello_world'  # <-- your sinatra app
require 'rspec'
require 'rack/test'

RSpec.describe 'The HelloWorld App' do
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  it "says hello" do
    get '/'
    expect(last_response).to be_ok
    expect(last_response.body).to eq('Hello World')
  end
end

通过 RSpec 包含 Rack::Test,使其对所有规范上下文可用

require 'rspec'
require 'rack/test'

RSpec.configure do |conf|
  conf.include Rack::Test::Methods
end

Test::Spec

Rack::Test 模块应该包含在 describe 块的上下文中

ENV['APP_ENV'] = 'test'

require 'hello_world'  # <-- your sinatra app
require 'test/spec'
require 'rack/test'

describe 'The HelloWorld App' do
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  it "says hello" do
    get '/'
    last_response.should.be.ok
    last_response.body.should.equal 'Hello World'
  end
end

通过在 Test::Unit::TestCase 中包含 Rack::Test,使其对所有规范上下文可用

require 'test/spec'
require 'rack/test'

Test::Unit::TestCase.send :include, Rack::Test::Methods

Capybara

Capybara 默认情况下将使用 Rack::Test。您可以通过设置 default_driver 使用其他驱动程序,例如 Selenium

ENV['APP_ENV'] = 'test'

require 'hello_world'  # <-- your sinatra app
require 'capybara'
require 'capybara/dsl'
require 'test/unit'

class HelloWorldTest < Test::Unit::TestCase
  include Capybara::DSL
  # Capybara.default_driver = :selenium # <-- use Selenium driver

  def setup
    Capybara.app = Sinatra::Application.new
  end

  def test_it_works
    visit '/'
    assert page.has_content?('Hello World')
  end
end

另请参阅

有关 getpostputdelete 及其相关方法的更多信息,请参阅 Rack::Test 的源代码。