Rails 3 + Rspec 2: тестирование content_for - PullRequest
14 голосов
/ 04 ноября 2011

Я использую Rails 3.1.1, RSpec 2.7.0 и HAML 3.1.3.

Допустим, у меня есть следующие файлы представлений:

app / views / layouts / 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
app / views / layouts / companies.html.haml
- content_for :content do
  #main
    = yield :main
  #sidebar
    = yield :sidebar

= render :template => 'layouts/application'
app / views / companies / index.html.haml
- content_for :main do
  %h1 MainHeader
- content_for :sidebar do
  %h1 SidebarHeader

И следующий файл спецификаций:

spec / views / companies / 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)

, он возвращает ноль.

  • Есть ли способ проверить content_for с точки зрения спецификации?
  • Есть лилучший способ структурировать файлы макета, чтобы я мог их протестировать и при этом достичь того же конечного результата?

Ответы [ 3 ]

27 голосов
/ 16 декабря 2011

Используя 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)

ps значение блока 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

Таким образом, ваша спецификация показывает, что именно делает ваш вид, независимо от макета.Для спецификации просмотра, я думаю, что это уместно проверить его изолированно.Всегда ли полезно писать спецификации вида?Это открытый вопрос.

Вместо этого, если вы хотите написать спецификации, показывающие, как выглядит разметка, предоставляемая пользователю, вам понадобится либо спецификация запроса, либо функция огурца.Третий вариант - это спецификация контроллера, которая включает в себя представления.

ps, если вам нужно было специфицировать представление, которое выводит некоторую разметку напрямую и делегирует другую разметку для 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 ().

1 голос
/ 15 ноября 2011

Из документов RSpec :

Чтобы предоставить макет для рендеринга, вам нужно явно указать и шаблон, и макет.

Я обновил спецификацию, и она прошла:

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
0 голосов
/ 11 ноября 2011

Не заморачивайся со спецификациями вида.Их сложно писать хорошо, и они не проверяют достаточно стека, чтобы его стоило использовать (особенно ввиду сложности написания).Вместо этого используйте Cucumber, и в ходе этого проверяйте свои представления.

Вы, как правило, тоже не хотите тестировать content_for, а именно: это реализация, и вместо этого вы должны тестировать поведение.Так что просто напишите свои истории о огурцах, чтобы они проверяли желаемый контент.

Если по какой-то странной причине вам нужно нужно протестировать content_for, RSpec имеет синтаксис, похожий на body[:content_name]или body.capture :content_name в зависимости от версии (или что-то в этом роде; давно не использовал).Но подумайте, есть ли лучший способ проверить то, что вы действительно хотите проверить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...