2014-10-09 3 views
0

у меня есть два атрибута внутри моей модели, которые разделяют те же валидацииRSpec - Тестирование ошибок для 2 атрибутов, которые разделяют ту же проверку (ы)

validates :first_name, :last_name, length: {minimum: 2} 

Прямо сейчас я атрибут :first_name испытываться следующим образом:

RSpec.describe User, :type => :model do 
    it 'is invalid if the first name is less than two characters' 
    user = User.create(
     first_name: 'a' 
    ) 
    expect(user).to have(1).errors_on(:first_name) 
end 

ради разработчика, который не знаком с тем, как я установки моей моделью, которую я хотел бы явно указать отношения двух атрибутов с чем-то вроде этого:

it 'is invalid if the first name and/or last name has less than two characters' 
    user = User.create(
    first_name: 'a', 
    last_name: 'b 
) 
    expect(user).to have(1).errors_on(:first_name, :last_name) 

Очевидно, что это бросает ошибку:

wrong number of arguments (2 for 0..1)

То же самое будет применяться, если я установил 2 два валидаций:

validates :first_name, :last_name, length: {minimum: 2}, format: {with: /^([^\d\W]|[-])*$/} 

И попытаться проверить на 2 ошибки:

it 'is invalid if the first name and/or last name has less than two characters and has special characters' 
    user = User.create(
    first_name: '@', 
    last_name: '# 
) 
    expect(user).to have(2).errors_on(:first_name, :last_name) 
+0

цель 'длины: {минимум: истинно}', чтобы убедиться, что это не пустой? – Anthony

+0

Спасибо, что указали это. Теперь изменилось на: 'length: {minimum: 2}'. Цель состоит в том, чтобы убедиться, что они печатают более двух символов. –

+0

Обновлен мой ответ. – Anthony

ответ

1

В RSpec 3.x, вы можете соединение ожидания с .and:

it 'is invalid if the first name and/or last name has less than two characters' do 
    user = User.create(first_name: 'a', last_name: 'b') 
    expect(user).to have(1).errors_on(:first_name).and have(1).errors_on(:last_name) 
end 

Отъезд документацию rspec-expectations для получения дополнительной информации.

Для RSpec 2.x, вам нужно сделать одну из них:

it 'is invalid if the first name and/or last name has less than two characters' do 
    user = User.create(first_name: 'a', last_name: 'b') 
    expect(user).to have(1).errors_on(:first_name) && have(1).errors_on(:last_name) 
end 

# or 
it 'is invalid if the first name and/or last name has less than two characters' do 
    user = User.create(first_name: 'a', last_name: 'b') 
    expect(user).to have(1).errors_on(:first_name) 
    expect(user).to have(1).errors_on(:last_name) 
end 

Это не так хороша, но она должна работать.

EDIT:

OP использует rspec-collection_matchers камень. Таможенные соединители этого драгоценного камня не включают в себя модуль смешивания RSpec 3 RSpec::Matchers::Composable, поэтому метод #and не распознается.

Есть несколько вещей, которые можно сделать, чтобы обойти эту проблему. Проще всего использовать технику && выше (в моих предложениях RSpec 2.x). Чтобы использовать только RSpec 3 matchers, вам нужно использовать be_valid:

it 'is invalid if the first name and/or last name has less than two characters' do 
    user = User.create(first_name: 'a', last_name: 'b') 
    expect(user).to_not be_valid 
end 

Конечно, это не различает first_name ошибок и last_name ошибки, как это первоначально предполагалось.Для того, чтобы сделать это с be_valid согласовани, вы должны разбить тест на два испытания:

it 'is invalid if the first name has less than two characters' do 
    user = User.create(first_name: 'a', last_name: 'abc') 
    expect(user).to_not be_valid 
end 

it 'is invalid if the last name has less than two characters' do 
    user = User.create(first_name: 'abc', last_name: 'a') 
    expect(user).to_not be_valid 
end 
+0

Я столкнулся с этой ошибкой 'undefined method 'и' for # ' –

+0

Я предположил, что вы работаете с RSpec 3.x. Я отредактировал свой ответ, чтобы отразить ваши варианты в RSpec 2.x. – Johnson

+0

Я предполагал, что и до сих пор. Первоначально у меня была такая настройка gemfile, как это: 'gem 'rspec-rails''. Но теперь, после того как вы упомянули об этом, я изменил его на: «gem» rspec-rails, «~> 3.0.0», но все же безрезультатно. Есть ли что-то еще, что мне нужно изменить в другом месте, чтобы указать на изменение версии? Я предположил, что не указывая номер версии, автоматически дал мне последнюю версию. –

0

Ваши тесты должны выглядеть так:

it 'invalid length' do 
    user = User.new(first_name: '@', last_name: '#') 
    user.valid? 
    expect(user.errors.count).to eq 2 
    expect(user.errors[:first_name]).to include "is too short (minimum is 2 characters)" 
    expect(user.errors[:last_name]).to include "is too short (minimum is 2 characters)" 
end 

Звонок user.valid? запустит нового пользователя против проверок, которые будут заполнять ошибки.

Это очень подробное испытание для проведения единичного испытания. Я настоятельно рекомендую shoulda matchers. Вы можете проверить выше всего две линии:

it { is_expected.to ensure_length_of(:first_name).is_at_least(2) } 
it { is_expected.to ensure_length_of(:last_name).is_at_least(2) } 
+0

Закончено получение этой ошибки; 'expected: 2 got: 8 (сравнивается с использованием ==)' –

+0

ну, я не думаю, что бит 'errors.count' - хороший предмет для тестирования. Очевидно, что у вас есть еще 6 других валидаций, которые не передаются с приведенным выше. Большинство советовали бы вам избавиться от этого ожидания. – Anthony

+0

Вы бы порекомендовали просто создать отдельные тесты для этих атрибутов? Я все для создания СУХОГО кода, но если он становится более сложным, чем необходимо, я открываю альтернативы. –