`

使用Rack进行Rails测试

阅读更多
Testing Rails with Rack::Test

The biggest news in Rails 2.3 is its support for Rack, the WSGI inspired Ruby web server interface. Of all the Rack goodness that has come along lately, the one that has me the most excited is Bryan Helmkamp’s Rack::Test library, of which Bryan said “Basically, I extracted Merb’s request helper code into a small, reusable, framework agnostic library.”

I loved Merb’s request specs. I suspect that I’m going to like Rack::Test too.
如何安装 Rack::Test

We’ll start by installing Rack::Test and loading it into our Rails app. Append this line to config/environments/test.rb:

引用
config.gem "rack-test", :lib => "rack/test"


You can now use rake to install it:

$ sudo rake gems:install RAILS_ENV=test


使用Rake运行Rack“rake test:rack”


We want to be able to run these tests easily with rake, just like our unit or functional tests. Create a new file called lib/tasks/rack-test.task and paste this code (courtesy of recipe 53 from the Advanced Rails Recipes book) into it:
namespace :test do
  Rake::TestTask.new(:rack => "db:test:prepare") do |t|
    t.libs << "test"
    t.pattern = "test/rack/**/*_test.rb"
    t.verbose = true
  end
  Rake::Task["test:rack"].comment = "Run the Rack::Test tests in test/rack"
end

task :test do
  Rake::Task["test:rack"].invoke
end


Note that we have also extended the :test task so that our Rack tests will get run after our unit and functional tests.

You should now be able to run rake test:rack, but it won’t do anything yet. Let’s test it by dropping this code into a file called test/rack/dummy_test.rb:

require File.join(File.dirname(__FILE__), *%w[.. test_helper])

class DummyTest < ActiveSupport::TestCase
  include Rack::Test::Methods

  def app
    lambda { |env| [200, {}, "Coolness"] }
  end

  test "should be hooked up properly" do
    get "/"
    assert last_response.body.include?("Cool")
  end
end

When you run rake test:rack you should get something like this:

$ rake test:rack
(in /Users/graham/data/effectif/projects/canvas)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I"lib:test" "/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/rack/login_test.rb" 
Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started

.
Finished in 0.008904 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

测试Rails应用

You’ll have noticed that the app method (which is supposed to return an instance of the Rack application under test) doesn’t actually have anything to do with Rails. It returns a callable object that needs to be compliant with the Rack API (apps are invoked via their call method, which is also how you invoke a lambda).

Let’s fix that by making the app method return an instance of our Rails application.

For an example of how Rails instantiates a rack app have a look inside commands/server.rb. Scroll down until you find the call to Rack::Builder.new. From there we can see that Rails is using ActionController::Dispatcher.new. That should be enough for most purposes (if not you can see what else you may need to add by poking around in server.rb).

That gives us a template test file that looks something like this:

require File.join(File.dirname(__FILE__), *%w[.. test_helper])

class MyTest < ActiveSupport::TestCase
  include Rack::Test::Methods

  def app
    ActionController::Dispatcher.new
  end

  test "home page" do
    get "/"
    assert last_response.ok?
  end
end


If you want to get a bit more fancy and test things that aren’t handled by ActionController::Dispatcher you can put your app together with Rack::Builder. As a contrived example, if you wanted to test for the presence of static files (I said it was contrived) you could create your app like this:
def app
  Rack::Builder.new {
    map "/" do
      use Rails::Rack::Static 
      run ActionController::Dispatcher.new
    end
  }.to_app
end


This article was written using Rails 2.3.2, Rack 1.0.0 and Rack::Test 0.3.0.
Why Bother?

Shortly after I first posted this article, crispee commented on reddit asking why you’d bother to use Rack::Test instead of the functional tests that come with Rails. It’s a good question, and I completely failed to cover it. Ooops.

Firstly, Rack::Test is more similar to the Rails integration tests than to the functional tests. Functional tests only allow you test the actions and views of a single controller. Rack::Test allows you to write tests that visit pages anywhere on your site – you can simulate the behaviour of a real browser to ensure that your entire app hangs together properly.

Secondly, both the Rails functional and integration tests are closely coupled to Rails. Imagine for a moment that you’ve been running a Rails app for a while now. You’ve invested a lot of effort in your application; users can log in and do all sorts of clever stuff. In the meantime you’ve been hand crafting the sales pages (e.g. home page, tour, FAQ, etc.) and adding them to your app. All these static pages are served by one big controller and your routes file is getting to be a bit of a mess. It’s high time that you introduced a CMS.

You’ve also recently stumbled across a hot new rack compatible web framework (for the sake of argument, let’s call it Sinatra). You quite fancy using a Sinatra CMS (sorry, shameless plug) while continuing to develop the main part of your application in Rails. Rack makes this very easy to do in the same Ruby process (see Rails meets Sinatra for details).

Obviously, you wrote a test to demonstrate that a new user can click on the “Buy Now” link on your home page, navigate their way through your signup forms, and end up on the home page. If you were also astute enough to write that test using Rack::Test, that test will still work after you move some of those pages into the Sinatra CMS.

If you refer to Pratik’s “Rails meets Sinatra” post that I linked to above, you’ll see that you’d only have to change the way the rack app is instantiated in your test:

def app
  Rack::Builder.new {
    # URLs starting with /account (logged in users) go to Rails
    map "/account" do
      run ActionController::Dispatcher.new
    end

    # Everything else goes to your CMS
    map "/" do
      run Sinatra.application
    end
  }.to_app
end


How awesome is that?
分享到:
评论

相关推荐

    Ruby-Split基于Rack的AB测试框架

    Split框架充分利用了Rack的特性,将A/B测试的逻辑无缝地集成到Ruby on Rails或其他Rack兼容的应用中。 首先,让我们深入了解一下什么是A/B测试。A/B测试是一种统计方法,用于比较两种或多种变体(如网页设计、营销...

    Rails进行敏捷Web开发(所有版本的源码rails3.0-4.0)

    Rails是Ruby语言的一个著名...- 测试框架如RSpec或Test::Unit的使用。 通过对这些版本的源码进行分析和学习,开发者不仅可以提升对Rails框架的理解,还能在实际项目中运用这些知识,编写出更高效、更安全的Web应用。

    rails api(文档)

    10. **测试**:测试是API开发的关键部分,Rails API支持RSpec、Minitest等多种测试框架,方便编写和执行API端点的测试用例。 Rails API文档是学习和开发这个框架的重要资源。它详细介绍了如何设置项目、配置路由、...

    The Rails 4 Way

    - **Rack**:Rack是Ruby Web应用的一个接口规范,Rails基于Rack实现了自己的请求处理流程。 - **ActionDispatch**:ActionDispatch是Rails中处理HTTP请求的核心模块,负责解析请求并将请求分发到合适的控制器方法。 ...

    Rails 3 in Action

    书中第二章提到 **测试驱动开发(TDD)** 和 **行为驱动开发(BDD)**,这两种方法是 Rails 社区广泛采用的测试策略。 - **测试驱动开发(TDD)**: - 测试先行:先编写测试用例,再编写满足这些测试的代码。 - 循环...

    rack-0.87.zip

    Rack在IT行业中是一个重要的组件,尤其在Ruby on Rails社区中,它作为Web服务器和Rails应用之间的接口。这个压缩包可能包含了Rack框架的源代码、配置文件、示例应用或者其他与0.87版本相关的开发资源。 描述 ...

    终于知道怎么把rails Web程序打包成可执行文件了

    总结起来,将Rails Web程序打包成可执行文件涉及多种方法,包括但不限于使用JRuby、Warbler、Rack、exe bundlers或者Docker。每种方法都有其优缺点,开发者需要根据目标平台、性能需求和部署环境来选择最适合的方案...

    The Rails 5 way 英文原版

    5. 其他技术细节:包括Rails的配置、日志的配置和使用,以及如何利用Rails的特性进行高效的测试。 本书还包含了一些附加内容,例如作者关于此书内容的前言、致谢、关于作者的简介、本书的目标、先决条件、许可证...

    Addison.Wesley.RailsSpace.Building.a.Social.Networking.Website.with.Ruby.on.Rails

    本书旨在通过实际开发一个面向Ruby on Rails社区的社交网络应用——RailsSpace,来教授读者如何使用Ruby on Rails进行Web开发。从静态页面到动态功能丰富的网站,本书将带领读者完成一系列实用的开发任务。 #### 二...

    The rails4 way

    - **Rack**: 讨论了作为Rails底层基础的Web服务器接口Rack的基本原理。 - **ActionDispatch**: 分析了Rails请求处理流程的起点——ActionDispatch组件的工作机制。 - **渲染视图**: 详细解释了如何通过控制器来...

    Rails API文档

    10. **Testing**:Rails内置了全面的测试支持,包括Unit测试、Functional测试和Integration测试,使用Test::Unit、MiniTest或RSpec框架进行编写。 以上是Rails API文档中涉及的主要内容。通过深入学习和理解这些...

    rails_routing_guide

    Rails允许开发者对路由进行精细的控制,包括指定使用的控制器、覆盖路由命名辅助方法、限制创建的路由、翻译路径等高级选项。 检查和测试路由 为了调试和验证路由的设置,Rails提供了列出现有路由和测试路由的工具...

    ruby on rails基础知识

    - **测试**: Rails提供了丰富的测试框架,包括单元测试、集成测试等。 #### 五、总结 通过本文的学习,您应该对Ruby on Rails的基本概念有了初步了解。Rails凭借其简洁高效的设计理念和强大的社区支持,成为了开发...

    rails-api-4.2.4

    Rails的核心优势在于其强大的数据库操作、自动化的测试工具和丰富的社区支持。 **Rails API 特性** 1. **轻量化**: Rails API 去除了视图层相关的组件,减少了不必要的依赖,使项目更加小巧,加载速度更快。 2. **...

    OmniAuth是一个使用Rack中间件的灵活的身份验证系统。.zip

    OmniAuth是一个强大的身份验证解决方案,它利用了Rack中间件的灵活性,为Ruby on Rails和其他使用Rack的应用程序提供了一种标准化的方式处理多种身份验证服务。Rack是Ruby web服务器接口,允许开发者构建自己的web...

    rack教程(ruby)

    在这个过程中,Rack负责接收来自应用服务器的请求并将其转换为一个标准化的数据结构,然后传递给Ruby Web应用进行处理。处理完成后,Rack再将应用的响应转换回应用服务器可以理解的形式,并最终返回给用户。 #### ...

    rails项目必备组件

    在给定的文件"red_gem"中,可能是一个Rails项目中使用的Gem(Ruby的扩展库)。Gem文件通常包含项目的依赖,例如上述提到的一些组件。通过安装和配置这些Gem,可以极大地提升Rails开发的效率和质量。为了具体了解"red...

Global site tag (gtag.js) - Google Analytics