2013-07-23 1 views
1

ВопросRspec2 + Rails4: Тестирование на отображенных модельных полей в форме частичной

Я хотел бы писать тесты, которые проверяют на модели поля, которые отображаются в моей «шоу» и «форма» обертонов. Мне удалось «показать», а не «форму».

Главное ограничение: решение должно иметь возможность прокручивать массив, содержащий все имена полей модели.

Я считаю, что этот случай может быть интересен всем, кто пытается сократить свои тестовые файлы сценариев, имея много полей и имея полный контроль над тем, что отображается, а что нет, поэтому я приложу некоторые усилия, пытаясь найти решение, с вашей помощью, если вы пожалуйста :)

вид Форма

Ничего особенного

= form_for @user do |f| 
    = f.select :field_1, options_from_collection_for_select ... 
    = f.text_field :field_2 
    ... 

Фактическая ситуация

Я нашел простой способ для «шоу» частичное, вот как мой файл спецификации выглядит следующим образом:

def user_fields_in_show_view 
    [:field_1, :field_2, ..., :field_n] 
end 

it 'display fields' do 
    user_fields_in_show_view.each do |field| 
    User.any_instance.should_receive(field).at_least(1).and_call_original 
    end 

    render 
end 

Это хорошо работает.

-

Но точно такой же метод не работает в "форме" частичный, используя один и тот же код

def user_fields_in_form_view # List of fields need to be different, because of the associations 
    [:field_1_id, :field_2, ..., :field_n] 
end 

it 'display fields' do 
    user_fields_in_form_view.each do |field| 
    User.any_instance.should_receive(field).at_least(1).and_call_original 
    end 

    render 
end 

Он скулит, как это:

Failure/Error: Unable to find matching line from backtrace 
Exactly one instance should have received the following message(s) but didn't: field1_id, field_2, ..., field_n 
# Backtrace is long and shows only rspec/mock, rspec/core, rspec/rails/adapters, and spork files 

Я до сих пор не установлено

1- Я прокомментировал фрагмент моих тестов и выводя на консоль rendered, чтобы вручную проверить, что создано моим представлением, и да, поля правильно сгенерированы.

2- я заменил User.any_instance моделью Поручаю к мнению, ошибка немного отличается, но он по-прежнему не работает

it 'display fields' do 
    user = create :user 
    assign :user, user 

    user_fields_in_form_view.each do |field| 
    user.should_receive(field).at_least(1).and_call_original 
    end 

    render 
end 

Дает:

Failure/Error: user.should_receive(field).at_least(1).and_call_original 
    (#<User:0x0000000506e3e8>).field_1_id(any args) 
     expected: at least 1 time with any arguments 
     received: 0 times with any arguments 

3- I измените код, так что it находится внутри цикла, например:

user_fields_in_form_view.each do |field| 
    it 'display fields' do 
    user = create :user 
    assign :user, user 

    user.should_receive(field).at_least(1).and_call_original 

    render 
    end 
end 

Такой же результат, как указано выше

И у меня заканчиваются варианты. Я подозреваю, что внутренности FormBuilder играют на меня плохой трюк, но я не могу понять, я еще не очень хорошо разбираюсь в них.Спасибо за чтение

+0

Что произойдет, если вы измените 'user.should_receive' на' User.any_instance.should_receive'? Работает ли тест в этом случае? – DNNX

+0

Более загадочное выходное сообщение, но все же не проходящее – Benj

+1

Хммм ... это интересно. Не могли бы вы показать код просмотра, пожалуйста? Кроме того, вы уверены, что вы вызываете 'first_name',' last_name' в коде? Возможно, есть такой код, как 'user.attributes.slice (* current_role.allowed_user_attrbutes) .each {| k, v | ...} '? – DNNX

ответ

2

Обычно я стараюсь написать единичный тест как можно проще. Петли в модульных тестах не добавляют большей читаемости и не очень хорошей практикой в ​​целом. Я бы переписать тест так:

it 'should display user name and email' do 
    # note: `build` is used here instead of `create` 
    assign :user, build(:user, first_name: 'John', last_name: 'Doe', email: '[email protected]') 

    render 

    rendered.should have_content 'John' 
    rendered.should have_content 'Doe' 
    rendered.should have_content '[email protected]' 
end 

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

<%= user.attributes.values_at('first_name', 'middle_name').compact.join(' ') %> 

Кроме того, несколько утверждений в одном тесте - плохой запах. Отправляясь один шаг дальше, я бы заменить этот тест с тремя меньшими:

it "should display user's first name" do 
    assign :user, build(:user, first_name: 'John') 
    render 
    expect(rendered).to include 'John' 
end 

it "should display user's last name" do 
    assign :user, build(:user, last_name: 'Doe') 
    render 
    expect(rendered).to include 'Doe' 
end 

it "should display user's email" do 
    assign :user, build(:user, email: '[email protected]') 
    render 
    expect(rendered).to include '[email protected]' 
end 

========

UPD: Давайте сделаем его более динамичным, чтобы избежать тонн повторение. Tis не ответы, почему ваш спецификации не удается, но, надеюсь, представляет рабочие испытания:

%i(first_name last_name email).each do |field| 
    it "should display user's #{field}" do 
    user = build(:user) 
    assign :user, user 
    render 
    expect(rendered).to include user.public_send(field) 
    end 
end 

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

+0

Спасибо за ваш ответ. Это хороший подход.Я отредактировал свой вопрос с дополнительной информацией, объясняющей, почему я пытаюсь сжать свой код с помощью циклов. Я буду ждать, если кто-нибудь придумает более «автоматическое» решение, чем ваше. – Benj

+0

См. Мое обновление. Это более или менее автоматическое. – DNNX

+0

Хорошо видно. Да, я уже это рассматривал (вы действительно дали мне эту идею своим оригинальным ответом), я сохраню ее в качестве резервного плана и буду копать немного больше, хотя, надеюсь, это решение, которое не полагается на значение – Benj

1

Я не совсем уверен, как вы создаете форму, но если вы используете помощники form_for, simple_form_for или formtastic_form_for, на самом деле вы используете другой объект. Вы что-то вроде писать (предположим, что основной form_for)

= form_for @user do |f| 

и все методы передаются на объект f. Теперь f.object будет указывать на @user, но это копия @user или @user сама, я не знаю. Поэтому я ожидаю, что User.any_instance должен работать.

Независимо от того, при выполнении теста просмотра не важно, как настроено содержимое поля, важно правильно установить содержимое поля. Предположим, что вы сами создаете свои формы, вы переключаетесь на другую библиотеку, чтобы создавать свои формы, и все ваши тесты ломаются, потому что они извлекают данные по-разному. И это не имеет значения.

Итак, я с @DNNX, и в ваших тестах просмотра вы должны проверить содержимое отображаемого HTML, а не как получить данные.

+0

Хорошо, это ясно. Я буду следовать за вашими парнями, советуя и полагаясь на ценности в своем тесте. Спасибо за ваше время и посоветуйте :) Cheers – Benj