2016-10-14 1 views
4

Так что в моих эволюционирующих rspecs для моей RoR модели, я закончил с двумя испытаниями точно так же:Держите DRY, но хочу повторить по разным причинам

it 'is valid when x is zero' do 
    foo = build(:foo, x: 0, y: 10) 
    expect(foo.valid?).to be_truthy 
end 
it 'is valid when y is ten' do 
    foo = build(:foo, x: 0, y: 10) 
    expect(foo.valid?).to be_truthy 
end 

Это произошло потому, что я написал спецификации для проверки x сначала, затем добавьте спецификацию для y после.

Очевидно, что время для рефакторинга. Я мог бы удалить одну из спецификаций, потому что они дубликаты: держите ее СУХОЙ.

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

Мои вопросы - приемлемо ли в этом случае сохранить неповторимые характеристики дубликатов, или я должен «объединить» их и переписать описание it? Возможно:

it 'is valid when x is zero and y is ten' do 
    foo = build(:foo, x: 0, y: 10) 
    expect(foo.valid?).to be_truthy 
end 

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

Есть ли другой подход, который я пропустил?

+0

вполне приемлемо, чтобы иметь оба теста ИМХО –

+0

Это зависит от многого. Должен ли первый тест пройти с 'y: nil'? с 'y: false'? с 'y: MyY.new'? Если нет, у вас уже проблемы. Нужно хотеть, что тестируется. Я бы пошел с 4 тестами для '{x, y} ∈ [good, bad]'. – mudasobwa

+1

Зачем проверять, что 'valid?' Является правдивым, когда вы можете использовать ['# be_valid'] (http://www.rubydoc.info/gems/rspec-rails/RSpec%2FRails%2FMatchers%3Abe_valid), например. 'ожидать (foo). to be_valid' идея абсолютно такая же и делает ее более читаемой, на мой взгляд. – engineersmnky

ответ

2

Я бы не стал беспокоиться о DRY и больше о написании спецификаций, которые фактически покрывают поведение, которое вы намереваетесь.

it 'is valid when x is zero' do 
    foo = build(:foo, x: 0) 
    expect(foo.valid?).to be_truthy 
end 

Этот пример на самом деле не распространяется на вашу валидацию вообще! Если вы прокомментируете валидацию в своей модели, она все равно пройдет.

Некоторые советы при тестировании модели валидаций:

  • Избегайте использования фабрик. Просто инициализируйте с помощью .new и тестируемого атрибута.
  • Тестирование как недействительного, так и допустимого ввода.
  • Опишите поведение проверки, а не какие значения приемлемы.
  • Проверяйте каждую проверку в изоляции - ваша интеграция и функциональные спецификации обычно охватывают проверки в целом.

RSpec.describe Foo do 
    describe "validations" do 
    describe 'x' do 
     it "validates that x is a number between 1 and 10" do 
     expect(Foo.new(500).valid?.errors[:x]).to include "must be less than or equal to 10". 
     expect(Foo.new(10).valid?.errors).to_not have_key :x 
     end 
    end 

    describe 'y' do 
     it "validates that y is a number that is less than 15" do 
     expect(Foo.new(500).valid?.errors[:y]).to include "must be less than 15". 
     expect(Foo.new(10).valid?.errors).to_not have_key :y 
     end 
    end 
    end 
end 
+0

Если вы хотите, чтобы высушить его, посмотрите на 'musta-matchers', который делает это намного более свободно. – max

+0

А, интересно - я всегда сфокусировался на проверке действительной записи. Следовательно, когда я позже добавил поле 'y', мне пришлось сохранить допустимую запись, добавив, таким образом,' y' для более старых тестов. Я могу видеть в ваших примерах. Каждый из них посвящен только тому, что он тестирует, не беспокоясь о других. –

+0

Я предпочитаю этот ответ, потому что мои тесты остаются СУХОЙ, и я вижу, что я не фокусировался на правильном тестировании. Благодаря! –

2

Как правило, я считаю, что наличие небольших независимых тестов важнее, чем сухих.

Однако, по-видимому, существует несогласованность в логике ваших тестов.

Если foo is всегда действительный, когда x равно нулю, вы должны иметь возможность отбросить значение y в первой спецификации.

it 'is valid when x is zero' do 
    foo = build(:foo, x: 0) 
    expect(foo.valid?).to be_truthy 
end 

И если Foo всегда справедливо, когда у есть десять, то вы должны быть в состоянии понизить й значение в этой спецификации.

it 'is valid when y is ten' do 
    foo = build(:foo, y: 10) 
    expect(foo.valid?).to be_truthy 
end 

Если это не так, то вы могли бы рассмотреть тестирования случаев более конкретно.

Например:

it 'allows x to equal zero' do 
    foo = build(:foo, x: 0) 
    foo.valid? 
    expect(foo.errors).to_not have_key(:x) 
end 

it 'allows y to be ten' do 
    foo = build(:foo, y: 10) 
    foo.valid? 
    expect(foo.errors).to_not have_key(:y) 
end 
1

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

Правила, связанные с практикой СУХОГО кода, не являются жесткими и быстрыми, а более эвристическими. Одной из основных целей хранения кода DRY является, прежде всего, техническое обслуживание. Когда-то люди (включая меня) чувствовали, что вы пытаетесь обеспечить, чтобы вы не повторялись нигде, ради того, чтобы не повторять себя. Если вы обнаружите, что добавляете излишнюю сложность ради того, чтобы только что-то писать что-то (мне нравится высказывание Сэнди Меца «Не так сухо», то вам нужно спросить себя: «Это действительно стоит усилий?» «Это сделать мой код более читабельным или поддерживаемым? ». Один тест, который, как мне кажется, является хорошей лакмусовой бумажкой, - это то, что экземпляры дублированного кода, которые вы написали, были написаны по разным причинам, например, этот экземпляр относится к побочному эффекту, который этот экземпляр предназначен для результата.

+2

Есть еще один, я думаю, что Джей Филдс: «Тесты (и DSL) должны быть DAMP, а не DRY (описательные и значащие фразы)». –

+0

Хм, это очень полезный совет, тест - это не просто предотвращение регрессий и сохранение развязки кода, они также должны служить документацией. Я буду держать DAMP в виду. –

Смежные вопросы