Rubocop 25 размер блока линии и тесты RSpec

типичный модульный тест RSpec широко использует вложенные блоки Ruby для структурирования кода и использования DSL "magic", чтобы спецификации читались как BDD-операторы:

describe Foo do
  context "with a bar" do
    before :each do
      subject { Foo.new().add_bar }
    end

    it "looks like a baz" do
      expect # etc

в идеальной спецификации каждый пример может быть относительно коротким и точным. Однако обычно внешние блоки растут до 100 строк плюс, потому что структура RSpec работает таким образом и не требует много примеров спецификаций, каждый из которых может иметь несколько строк конкретной настройки, чтобы добраться до describe блоки, которые имеют тот же размер или больше, чем код для описываемого объекта.

недавнее обновление Rubocop ввело в игру новое правило, что блоки должны быть не длиннее 25 строк. Я не уверен в обосновании этого, потому что он не указан в руководство по стилю Ruby. Я понимаю, почему это может быть хорошо, и добавлено в набор правил по умолчанию. Однако после обновления наш тест Rubocop несколько раз терпит неудачу с такими сообщениями, как tests/component_spec.rb:151:3: C: Block has too many lines. [68/25]

С помощью метрических инструментов кода, таких как Rubocop, I как чтобы иметь политику " использовать значения по умолчанию, ссылку на руководство по стилю, работа выполнена.(главным образом потому, что обсуждение вкладок против пробелов и других мелочей тратит время, и IME никогда

в ответ мы просто установили правило размера блока Rubocop на высокий порог. Но это заставляет меня задуматься - что я упускаю? Использует ли RSpec теперь дискредитированный подход для макета кода, и что разумный options должен ли я уменьшить размеры блоков в наших тестах RSpec? Я вижу способы реструктуризации кода, чтобы избежать больших блоков, но они без исключения уродливые хаки, предназначенные исключительно для соблюдения правила Rubocop, например, блоки в вспомогательные функции:

def looks_like_a_baz
  it "looks like a baz" do
         expect # etc
  end
end

def bar_context
  context "with a bar" do
    before :each do
      subject { Foo.new().add_bar }
    end
    looks_like_a_baz
  end
end


describe Foo do
  bar_context
  # etc

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

есть ли что-нибудь еще я могу сделать, кроме как найти способы, чтобы игнорировать его?


ближайший существующий вопрос, который я мог найти по этой теме, был RSpec & Rubocop / Ruby Руководство По Стилю и это вполне разрешимые редактирование шаблонов тестов.

2 ответов


недавнее обновление Rubocop ввело в игру новое правило, что блоки должны быть не длиннее 25 строк. Я не уверен в обосновании этого, потому что он не указан в руководстве по стилю Ruby.

раньше все полицейские были основаны на руководстве Ruby Style, и RuboCop был способом придерживаться практики, установленной сообществом.

направление изменилось с тех пор, и область RuboCop расширилась, чтобы помочь разработчикам обеспечить согласованность в их кодовых базах в целом. Это привело к двум вещам:

  1. менты (даже те, которые основаны на руководстве по стилю Ruby) теперь в основном конфигурируются.
  2. есть полицейские для вещей, которые не упоминаются в руководстве по стилю Ruby, но по-прежнему полезны для обеспечения согласованности в проекте.

этот полицейский относится ко второй категории.

RSpec использует теперь дискредитированный подход для макета кода, и что разумные варианты должен ли я уменьшить размеры блоков в наших тестах RSpec?

короткий ответ-нет. DSL-языки по-прежнему прохладно. :-)

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

теперь RuboCop довольно умный, но он не знает, что такое DSL и нет, поэтому мы не можем автоматически игнорировать их. Можно утверждать, что мы могли бы исключить методы ввода DSL популярных фреймворков, таких как Rails routes и спецификации RSpec. Причины, по которым этого не делается, в первую очередь:

  1. ложноотрицательных результатов. Любой класс может реализовать метод, берущий блок, с тем же именем.
  2. RuboCop-это инструмент анализа Ruby и не должен знать о внешняя библиотека. (Исключая /spec каталог является любезностью, пока у нас нет надлежащей системы расширения, и это может быть обработано rubocop-rspec камень.)

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

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

в ответ мы просто установили правило размера блока Rubocop на высокий порог. Но это заставляет меня задуматься - что я упускаю?

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

  1. файлы, содержащие чисто декларативные DSL, например Rails routes, спецификации RSpec.
  2. файлы, которые имеют декларативный DSL, смешанный в основном императивный код, например aasm объявление государственной машины в модели Rails.

в первом случае лучшим решением является исключение файла или каталога, а во втором-использование встроенного отключения.

в вашем случае, вы должны обновить свой .rubocop.yml с:

Metrics/BlockLength:
  Exclude:
    - 'Rakefile'
    - '**/*.rake'
    - 'test/**/*.rb'

(обратите внимание, что вам нужно повторно повторить основные исключения из конфигурации по умолчанию, так как список будет перезаписан.)


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


если определенный блок обычно слишком длинный, я указываю его, а не файлы

Metrics/BlockLength:
  ExcludedMethods: ['describe', 'context']