测试 Rails 3 控制器时出现一些意外错误

发布于 2024-11-15 09:51:29 字数 6989 浏览 1 评论 0原文

我有一个这样定义的服务模型:

class Service < ActiveRecord::Base
  attr_accessible :service_type #, ...

  SERVICE_TYPES = {
    :restaurant => "restaurant",
    :retailer   => "retailer"
  }

  SERVICE_TYPES.values.each do |method|
   define_method method.pluralize.to_sym do
      where(:service_type => method)
   end
  end

  def domestic
    where(:country => 'USA')
  end

  def international
    where("country != 'USA'")
  end
end

我决定不对不同的服务使用传统的 STI 模式,因为它们都具有相同的属性,并且在其他方​​面表现相同。有一个父模型,但它仅用于规范化目的,Web 用户永远不需要知道它。就应用程序而言,存在服务类型以及这些类型下的特定服务。所以基本上我想要这样的 URL:

http://myapp/services        # <- Lists all service types
http://myapp/restaurants     # <- Lists all restaurant-type services
http://myapp/restaurants/foo # <- Lists a specific restaurant (using friendly_id gem)
http://myapp/retailers       # <- Lists all retailer-type services
http://myapp/retailers/bar   # <- Lists a specific retailer

所以我创建了一个像这样的路由模式:

controller :services, :via => [:get] do 
  match '/services'          => :index
  match '/:service_type'     => :service_index, :as => 'service_type', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
  match '/:service_type/:id' => :show,          :as => 'service',      :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
end

这让我明白了

    services GET  /services(.:format)                              {:controller=>"services", :action=>"index"}
service_type GET  /:service_type(.:format)                         {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"service_index"}
     service GET  /:service_type/:id(.:format)                     {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"show"}

控制器被定义为

class ServicesController < ApplicationController
  def index
    @service_types = Service::SERVICE_TYPES.values
    @page_title = "Services"
  end

  def service_index
    @service_type  = params[:service_type]
    @domestic      = Service.send(@service_type).domestic
    @international = Service.send(@service_type).international
    @page_title    = @service_type.capitalize
  end

  def show
    @service = Service.find(params[:id])
    @page_title = "Services - #{@service.name}"
  end
end

当我在浏览器中测试它时,这一切都按预期工作。但是当我尝试在 Rspec2 中运行集成测试时,我遇到了一些非常意外的行为。

require 'spec_helper'

describe ServicesController do
  describe "GET 'index'" do
    it "should be successful" do
      get :index
      response.should be_success
    end

    it "should have the right title" do
      get :index
      response.should have_selector(
        "title", 
        :content => "#{@base_title}Services"
      )
    end

    it "should have a link to each service" do
      get :index
      Service::SERVICE_TYPES.values.each do |service_type|
        response.should have_selector("a", :href => service_type_path(service_type.pluralize),
                                           :content => service_type.pluralize)
      end
    end
  end

  describe "GET 'service_index'" do
    Service::SERVICE_TYPES.values.each do |service_type|
      context service_type.pluralize do
        it "should be successful" do
          get :service_index, :service_type => service_type.pluralize
          response.should be_success
        end

        it "should have the right title" do
          get :service_index, :service_type => service_type.pluralize
          response.should have_selector(
            "title", 
            :content => "#{@base_title}#{service_type.pluralize.capitalize}"
          )
        end

        it "should have a link to each service" do
          get :service_index, :service_type => service_type.pluralize
          Service.send(service_type.pluralize).each do |service|
            response.should have_selector("a", :href => service_path(service_type.pluralize, service),
                                               :content => service.name)
          end
        end
      end
    end
  end

  describe "GET 'show'" do
    it "should be successful" do
      get 'show'
      response.should be_success
    end
  end
end

get 操作似乎运行成功,因为 “应该成功” 测试全部通过,但其他操作失败,因为它无法在页。奇怪的是,返回的 HTML 转储似乎不是来自我的应用程序。

  1) ServicesController GET 'index' should have the right title
     Failure/Error: response.should have_selector(
       expected following output to contain a <title>Services</title> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:12:in `block (3 levels) in <top (required)>'

  2) ServicesController GET 'index' should have a link to each service
     Failure/Error: response.should have_selector("a", :href => service_type_path(service_type.pluralize),
       expected following output to contain a <a href='/restaurants'>Restaurants</a> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:21:in `block (4 levels) in <top (required)>'
     # ./spec/controllers/services_controller_spec.rb:20:in `each'
     # ./spec/controllers/services_controller_spec.rb:20:in `block (3 levels) in <top (required)>'

  3) ServicesController GET 'service_index' restaurants should have the right title
     Failure/Error: response.should have_selector(
       expected following output to contain a <title>Restaurants</title> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:37:in `block (5 levels) in <top (required)>'

  4) ServicesController GET 'service_index' restaurants should have a link to each service
     Failure/Error: response.should have_selector("a", :href => service_path(service_type.pluralize, service),
       expected following output to contain a <a href='/restaurants/foo'>Foo</a> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:46:in `block (6 levels) in <top (required)>'
     # ./spec/controllers/services_controller_spec.rb:45:in `block (5 levels) in <top (required)>'

如果这确实是一个失败,我期望看到的是我的 HTML 应用程序模板的完整转储,该模板以 HTML 5 标记。相反,我只得到标记为 HTML 4 的页面的文档类型。

任何想法是什么会导致这样的情况吗?

作为次要问题,我无法找到任何方法来打开 Webrat 中的日志记录以查看实际发生的 HTTP 活动。我怎样才能做到这一点?

I have a services model defined as such:

class Service < ActiveRecord::Base
  attr_accessible :service_type #, ...

  SERVICE_TYPES = {
    :restaurant => "restaurant",
    :retailer   => "retailer"
  }

  SERVICE_TYPES.values.each do |method|
   define_method method.pluralize.to_sym do
      where(:service_type => method)
   end
  end

  def domestic
    where(:country => 'USA')
  end

  def international
    where("country != 'USA'")
  end
end

I decided to not use a traditional STI pattern for the different services because they will all have the same attributes and otherwise behave identically. There is a parent model, but it is used only for normalization purposes and the web user never needs to know about it. As far as the application goes, there are service types, and specific services under those. So basically I want URLs like this:

http://myapp/services        # <- Lists all service types
http://myapp/restaurants     # <- Lists all restaurant-type services
http://myapp/restaurants/foo # <- Lists a specific restaurant (using friendly_id gem)
http://myapp/retailers       # <- Lists all retailer-type services
http://myapp/retailers/bar   # <- Lists a specific retailer

So I created a routing pattern like so:

controller :services, :via => [:get] do 
  match '/services'          => :index
  match '/:service_type'     => :service_index, :as => 'service_type', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
  match '/:service_type/:id' => :show,          :as => 'service',      :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
end

Which gets me

    services GET  /services(.:format)                              {:controller=>"services", :action=>"index"}
service_type GET  /:service_type(.:format)                         {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"service_index"}
     service GET  /:service_type/:id(.:format)                     {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"show"}

And the controller is defined as

class ServicesController < ApplicationController
  def index
    @service_types = Service::SERVICE_TYPES.values
    @page_title = "Services"
  end

  def service_index
    @service_type  = params[:service_type]
    @domestic      = Service.send(@service_type).domestic
    @international = Service.send(@service_type).international
    @page_title    = @service_type.capitalize
  end

  def show
    @service = Service.find(params[:id])
    @page_title = "Services - #{@service.name}"
  end
end

This all works as expected when I test it in the browser. But when I try to run an integration test in Rspec2 I'm getting some really unexpected behavior.

require 'spec_helper'

describe ServicesController do
  describe "GET 'index'" do
    it "should be successful" do
      get :index
      response.should be_success
    end

    it "should have the right title" do
      get :index
      response.should have_selector(
        "title", 
        :content => "#{@base_title}Services"
      )
    end

    it "should have a link to each service" do
      get :index
      Service::SERVICE_TYPES.values.each do |service_type|
        response.should have_selector("a", :href => service_type_path(service_type.pluralize),
                                           :content => service_type.pluralize)
      end
    end
  end

  describe "GET 'service_index'" do
    Service::SERVICE_TYPES.values.each do |service_type|
      context service_type.pluralize do
        it "should be successful" do
          get :service_index, :service_type => service_type.pluralize
          response.should be_success
        end

        it "should have the right title" do
          get :service_index, :service_type => service_type.pluralize
          response.should have_selector(
            "title", 
            :content => "#{@base_title}#{service_type.pluralize.capitalize}"
          )
        end

        it "should have a link to each service" do
          get :service_index, :service_type => service_type.pluralize
          Service.send(service_type.pluralize).each do |service|
            response.should have_selector("a", :href => service_path(service_type.pluralize, service),
                                               :content => service.name)
          end
        end
      end
    end
  end

  describe "GET 'show'" do
    it "should be successful" do
      get 'show'
      response.should be_success
    end
  end
end

The get action appears to run successfully because the "should be successful" tests all pass, but the others fail because it can't find the proper selector(s) on the page. The odd thing is that the dump of HTML that is returned doesn't appear to come from my app.

  1) ServicesController GET 'index' should have the right title
     Failure/Error: response.should have_selector(
       expected following output to contain a <title>Services</title> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:12:in `block (3 levels) in <top (required)>'

  2) ServicesController GET 'index' should have a link to each service
     Failure/Error: response.should have_selector("a", :href => service_type_path(service_type.pluralize),
       expected following output to contain a <a href='/restaurants'>Restaurants</a> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:21:in `block (4 levels) in <top (required)>'
     # ./spec/controllers/services_controller_spec.rb:20:in `each'
     # ./spec/controllers/services_controller_spec.rb:20:in `block (3 levels) in <top (required)>'

  3) ServicesController GET 'service_index' restaurants should have the right title
     Failure/Error: response.should have_selector(
       expected following output to contain a <title>Restaurants</title> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:37:in `block (5 levels) in <top (required)>'

  4) ServicesController GET 'service_index' restaurants should have a link to each service
     Failure/Error: response.should have_selector("a", :href => service_path(service_type.pluralize, service),
       expected following output to contain a <a href='/restaurants/foo'>Foo</a> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:46:in `block (6 levels) in <top (required)>'
     # ./spec/controllers/services_controller_spec.rb:45:in `block (5 levels) in <top (required)>'

What I would expect to see if this was indeed a failure would be the complete dump of my HTML application template which is marked up in HTML 5. Instead I'm getting only the doctype of a page marked up as HTML 4.

Any ideas what would cause that?

As a secondary issue, I can't figure out any way to turn on logging in Webrat to see what HTTP activity is actually happening. How can I do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧时光的容颜 2024-11-22 09:51:29

是的,没关系。我是个白痴,忘记将 render_views 放入我的测试中这就是为什么它没有渲染视图

Yeah, never mind. I'm an idiot and forgot to put render_views inside my test which is why it wasn't rendering the view.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文