【问题标题】:Rails 3 + Rspec 2: Testing content_forRails 3 + Rspec 2:测试 content_for
【发布时间】:2011-12-22 06:40:02
【问题描述】:

我正在运行 Rails 3.1.1、RSpec 2.7.0 和 HAML 3.1.3。

假设我有以下视图文件:

应用程序/视图/布局/application.html.haml
!!!
%html
  %head
    %title Test
    = stylesheet_link_tag "application"
    = javascript_include_tag "application"
    = csrf_meta_tags

  %body
    = content_for?(:content) ? yield(:content) : yield
应用程序/视图/布局/companies.html.haml
- content_for :content do
  #main
    = yield :main
  #sidebar
    = yield :sidebar

= render :template => 'layouts/application'
应用程序/视图/公司/index.html.haml
- content_for :main do
  %h1 MainHeader
- content_for :sidebar do
  %h1 SidebarHeader

还有以下规范文件:

规范/视图/公司/index_spec.rb
require 'spec_helper'

describe 'companies/index.html.haml' do

  it 'should show the headers' do
    render
    rendered.should contain('MainHeader')
    rendered.should contain('SidebarHeader')
  end

end

当我运行 RSpec 时,我收到以下错误:

1) companies/index.html.haml should show the headers
   Failure/Error: rendered.should contain('MainHeader')
     expected the following element's content to include "MainHeader":
   # ./spec/views/companies/index_spec.rb:7:in `block (2 levels) in <top (required)>'

起初,我认为 RSpec 在渲染视图文件时以某种方式丢失了 content_for 块。但是,我无法在 RSpec 的 github 存储库中找到任何与此相关的问题,所以我不确定这应该归咎于谁。

我在http://www.dixis.com/?p=571 找到了一个(最近的)解决方案。但是,当我尝试建议的代码时

view.instance_variable_get(:@_content_for)

它返回 nil。

  • 有没有办法在视图规范中测试 content_for?
  • 有没有更好的方法来构建我的布局文件,这样我实际上能够测试它们并仍然获得相同的最终结果?

【问题讨论】:

    标签: ruby-on-rails-3 haml rspec2


    【解决方案1】:

    不要打扰视图规格。他们很难写好,而且他们没有测试足够多的堆栈值得使用(特别是考虑到写作困难)。相反,请使用 Cucumber,并在此过程中测试您的视图。

    您通常也不想专门测试content_for:那是实现,而您应该测试行为。因此,只需编写您的 Cucumber 故事,以便他们测试所需的内容。

    如果出于某种奇怪的原因确实需要测试 content_for,RSpec 的语法类似于 body[:content_name]body.capture :content_name,具体取决于版本(或类似的东西;haven'有一段时间没用过)。但请仔细考虑是否有更好的方法来测试您真正想要测试的内容。

    【讨论】:

    • 恕我直言,装饰器或演示器可用于使不编写视图规范变得可以,也可以使您的视图干燥甚至使它们无逻辑。但我们不应该仅仅停留在说“不要打扰视图规范”——这有点太笼统了。
    • @MarnenLaibow-Koser 的表现可能。我编写了请求规范来测试每个应用程序页面上的元标记,但是它们太慢了,我发现自己不愿意运行它们。目前正在翻译它们以查看规范,初步结果表明它们更快。
    • @evanrmurphy 它们可能更快,但它们不会测试您实际需要测试的内容。 (实际上也不要求规范——Cucumber 在这方面更好——但它们的错误比查看规范要少。)尤其是在您的测试代码中,首先要考虑正确性,然后再考虑性能。
    • 放大我的最后一句话:一个不正确的测试可以说比没有更糟糕,因为它给你一种错误的感觉,即你的应用程序是正确的。
    • 顺便说一句,视图规范错误且无用的一个主要原因是它们测试了特定的视图文件,但它们或其他任何东西都不能保证该视图文件实际上是由控制器呈现的。跨度>
    【解决方案2】:

    来自RSpec docs

    要为渲染提供布局,您需要明确指定模板和布局。

    我更新了规范并通过了:

    require 'spec_helper'
    
    describe 'companies/index.html.haml' do
    
      it 'should show the headers' do
        render :template => 'companies/index', :layout => 'layouts/companies'
        rendered.should contain('MainHeader')
        rendered.should contain('SidebarHeader')
      end
    
    end
    

    【讨论】:

      【解决方案3】:

      将 Rspec 2 与 Rails 3 一起使用,为了编写用于 content_for 的视图规范,请执行以下操作:

      view.content_for(:main).should contain('MainHeader')
      # instead of contain() I'd recommend using have_tag (webrat)
      # or have_selector (capybara)
      

      附言默认情况下 content_for(...) 块的值是一个空字符串,所以如果你想 编写说明 content_for(:main) 没有被调用的情况,使用:

      view.content_for(:main).should be_blank
      

      你的规范可以写成:

      it "should show the headers" do
        render
        view.content_for(:main).should contain('MainHeader')
        view.content_for(:side_header).should contain('SidebarHeader')
      end
      

      这样,您的规范就可以准确地显示您的视图所做的事情,而与任何布局无关。对于视图规范,我认为单独测试它是合适的。编写视图规范总是有用的吗?这是一个悬而未决的问题。

      相反,如果您想编写规范以显示提供给用户的标记是什么样的,那么您将需要请求规范或黄瓜功能。第三种选择是包含视图的控​​制器规范。

      附言如果您需要指定一个直接输出一些标记并将其他标记委托给 content_for() 的视图,您可以这样做:

      it "should output 'foo' directly, not as a content_for(:other) block" do
         render
         rendered.should contain('foo')
         view.content_for(:other).should_not contain('foo')
      end
      it "should pass 'bar' to content_for(:other), and not output 'bar' directly" do
         render
         rendered.should_not contain('bar')
         view.content_for(:other).should contain('bar')
      end
      

      这可能是多余的,但我只是想展示render() 如何填充render 和view.content_for。 “rendered”包含视图直接产生的任何输出。 "view.content_for()" 查找视图通过 content_for() 委托的任何内容。

      【讨论】:

      • 我发现这非常有用。但是,我使用的是 Rspec 2.8,并且使用 contain 会引发错误 undefined method 'contain' for #&lt;RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x98acd1c&gt;。但我只是使用== 代替view.content_for(:other).should == 'bar',效果很好。
      • 感谢您的积极反馈!如果您想测试子字符串并且您的 rspec 副本不支持“包含”,则可以使用“包含”:view.content_for(:other).should include('bar')。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      相关资源
      最近更新 更多