Rails / Rspec - написание спецификации для метода делегата (опция allow_nil) - PullRequest
6 голосов
/ 03 февраля 2012

Учитывая код ниже:

(1) Как вы будете писать спецификацию для проверки опции: allow_nil => false?

(2) Стоит ли даже писать спецификации для тестирования?

class Event < ActiveRecord::Base
  belongs_to :league

  delegate :name, :to => :league, :prefix => true, :allow_nil => false
end

describe Event do

  context 'when delegating methods to league object' do
    it { should respond_to(:league_name) }
  end

end

На самом деле было бы неплохо, если бы вы могли продлить выполнение musta:

it { should delegate(:name).to(:league).with_options(:prefix => true, :allow_nil => false) }

Ответы [ 3 ]

9 голосов
/ 27 февраля 2012

В соответствии с документацией для модуля delegate rails:

Если объект делегата равен nil, возникает исключение, и это происходит независимо от того, отвечает ли nil на делегированный метод.Вместо этого вы можете получить nil с опцией: allow_nil.

Я бы создал объект Event event с nil league или установил event.league = nil, затем попытался бы вызвать event.nameи проверьте, что это вызывает исключение, так как это то, что должно происходить, когда allow_nil ложно (что также является значением по умолчанию).Я знаю, что в rspec есть такая идиома для тестирования исключений:

lambda{dangerous_operation}.should raise_exception(optional_exception_class)

Я не уверен, есть ли у конструкции musta такая конструкция, хотя есть несколько статей, довольно старых, о том, как получить такое поведение в musta.

Я думаю, что это стоит проверить, если поведение этого класса может ожидать или предполагать, что произойдут пользователи этого класса - что, я думаю, вероятно верно в этом случае.Я бы не стал расширять musta для проверки «делегировать», потому что это кажется более зависимым от реализации: вы действительно говорите, что ваше событие должно вызывать исключение, если вы пытаетесь вызвать #name, когда у него нулевая лига .Для пользователей Event совершенно неважно, как вы это делаете.Я бы даже зашел так далеко, если вы хотите заявить и отметить это поведение, чтобы проверить, что Event#name имеет ту же семантику, что и League#name, без , не упоминая о delegate, посколькуэто подход, ориентированный на поведение.

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

Вы можете выделить такую ​​ситуацию, представив, какие могут быть сбои, если вы измените свой код так, чтобы пользователи Event не заботились.Если они не заботятся об этом, тест не должен прерываться, когда вы меняете его.Что если вы захотите, например, самостоятельно обработать делегирование, написав функцию #name, которая сначала регистрирует или увеличивает счетчик, а , а затем делегирует league?протестировав поведение, вызывающее исключения, вы защищены от этого изменения, но, проверив, является ли Event делегатом, вы прервете этот тест, когда внесете это изменение - и поэтому ваш тест не смотрел на то, что на самом деле важно о звонке на #name.

Во всяком случае, это все только разговоры в мыльной коробке.tl; dr: протестируйте, если это поведение, на которое кто-то может положиться.Все, что не было проверено, это кот Шредингера: сломанный и не сломанный одновременно.По правде говоря, большую часть времени это может быть хорошо: вопрос вкуса, хотите ли вы сказать что-то строгое и окончательно о том, как должна вести себя система, или просто позволить ей быть «неопределенным поведением».

3 голосов
/ 28 февраля 2012

Итак, пара вещей о том, проверять это или нет:

1) Я не думаю, что что-то не так с определением этого поведения. Если у вас есть пользователи, которым необходимо изучить ваше программное обеспечение / библиотеку, часто очень полезно убедиться, что все ваши методы, являющиеся частью вашего публичного контракта, определены. Если вы не хотите вносить эту часть в API этой модели, я мог бы порекомендовать выполнить делегирование вручную, чтобы не показывать внешнему миру больше методов, чем нужно.

2) Спецификации такого рода помогают гарантировать, что ваш договор с объектом, которому вы делегируете, остается в силе. Это особенно полезно, если вы используете в своих тестах заглушки и макеты, поскольку они часто реализуют один и тот же контракт, поэтому, по крайней мере, вы знаете, когда этот контракт изменяется.

Что касается того, как вы тестируете его часть allow_nil, я бы согласился с Мэттом, лучшая идея - убедиться, что лига равна нулю, а затем попытаться назвать имя в лиге. Это вы можете проверить, чтобы убедиться, что ноль возвращается.

Надеюсь, это поможет.

0 голосов
/ 25 ноября 2018

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

describe '#league_name' do
  let(:event) { create(:event) }

  after { event.league_name }

  it "delegates to league's name with prefix" do
     expect(event.league).to receive(:name)
  end
end
...