web-dev-qa-db-ja.com

Rubocop 25ラインブロックサイズとRSpecテスト

典型的なRSpec単体テストでは、ネストされたRubyブロックを広範囲に使用して、コードを構造化し、DSLの「マジック」を使用して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

理想的な仕様では、各例は比較的短く正確です。ただし、RSpec構造はこのように機能し、describe説明されているサブジェクトのコードと同じサイズまたはそれよりも大きいブロック。

最近のRubocopのアップグレードにより、ブロックが25行を超えてはならないという新しいルールが導入されました。 Rubyスタイルガイド に記載されていないため、その理由はわかりません。なぜそれが良いことなのかがわかり、デフォルトのルールセットに追加されました。ただし、アップグレード後、Rubocopテストはtests/component_spec.rb:151:3: C: Block has too many lines. [68/25]のようなメッセージで複数回失敗します

Rubocopなどのコードメトリックツールでは、Ilikeのポリシーを使用して、「デフォルトを使用、スタイルガイドへのリンク、ジョブ完了」というポリシーを設定します。 (主にタブとスペースおよび他の特徴点の議論が時間を浪費し、IMEneverが解決されるため)これは明らかに不可能であり、2つのコアデータ品質ツールはコードレイアウトアプローチに同意しません-または、少なくともそれが結果の解釈方法です。仕様の記述方法に本質的に問題はありません。

それに応じて、Rubocopブロックサイズルールを高いしきい値に設定するだけです。しかし、それは私が不思議に思う-私は何が欠けていますか? RSpecは現在、コードレイアウトに信用されていないアプローチを使用していますか?また、RSpecテストでブロックサイズを削減するためにどのreasonableオプションが必要ですか?大きなブロックを回避するためにコードを再構築する方法を見ることができますが、それらは例外なく、Rubocopのルールを純粋に満たすことを意図したexceptionいハックです。すべてのブロックをヘルパー関数に分割します。

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 Style Guide でした。これはテストテンプレートを編集することで解決可能に見えました。

56
Neil Slater

最近のRubocopのアップグレードにより、ブロックが25行を超えてはならないという新しいルールが導入されました。 Rubyスタイルガイドにリストされていないため、その理由はわかりません。

以前は、すべての警官はRuby Style Guideに基づいていましたが、RuboCopはコミュニティによって設定された慣行に従う方法でした。

それ以来、方向が変わり、RuboCopの範囲が拡大して、開発者が一般にコードベースの一貫性を確保できるようになりました。これにより、次の2つのことが起こりました。

  1. 警官(The Ruby Style Guide)に基づくものも)は、現在ほとんど構成可能です。
  2. Ruby Style Guide)に記載されていないものの警官がいますが、それでもプロジェクトの一貫性を強化するのに役立ちます。

この警官は2番目のカテゴリに分類されます。

RSpecはコードレイアウトに信用を失ったアプローチを使用していますか?また、RSpecテストでブロックサイズを小さくするには、どのような合理的なオプションが必要ですか?

短い答えはノーです。 DSLはまだクールです。 :-)

この警官は、命令型プログラミングの意味での大きなブロックを対象としています。一般的なガイドとして、DSLには適用されません。DSLはしばしば宣言的です。たとえば、Railsに長いroutes.rbファイルがあるのは完全に無害です。スタイル違反ではなく、大規模なアプリケーションの自然な結果です。本当に素晴らしいです。)

現在、RuboCopはかなりスマートですが、DSLが何であるかがわからないため、自動的に無視することはできません。 RailsルートやRSpec仕様などの一般的なフレームワークのDSLエントリメソッドを除外できると主張することができます。そうしない理由は主に次のとおりです。

  1. 偽陰性。すべてのクラスは、同じ名前でブロックを取得するメソッドを実装できます。
  2. RuboCopはRuby分析ツールであり、外部ライブラリについて実際に知ってはいけません。/specディレクトリを除外することは、適切な拡張システムができるまでは礼儀です。 rubocop-rspec gemによって処理されます。)

つまり、これは実行可能ですが、このように仕様例の束をヘルパー関数に変換することは、RSpec設計で推奨される読みやすいアプローチの反対のようです。

肝心なのは、RuboCopはより良いコードを書くのに役立つことです。私たちのアプリケーションの設計がそれ以外の点で健全であり、RuboCopを喜ばせるためだけに物事を読みにくくしていることに気付いた場合、警官をフィルタリング、構成、または無効にする必要があります。 :-)

それに応じて、Rubocopブロックサイズルールを高いしきい値に設定するだけです。しかし、それは私が不思議に思う-私は何が欠けていますか?

これはかなり鈍いツールであり、あなたがほのめかしているように、おそらくあなたはそれのためにいくつかの偽陰性を持つでしょう。この警官には2種類の誤検知があります。

  1. 純粋に宣言的なDSLを含むファイル。 Railsルート、RSpec仕様。
  2. 宣言型DSLがほとんど命令型コードに混在しているファイル。 Railsモデルのaasmステートマシン宣言。

前者の場合、ファイルまたはディレクトリを除外するのが最善の解決策であり、後者ではインライン無効化を使用するのが最善の解決策です。

あなたの場合は、.rubocop.ymlを次のように更新する必要があります。

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

(リストが上書きされるため、デフォルトの構成から基本的な除外を再度繰り返す必要があることに注意してください。)

74
Drenmi

特定のブロックが通常長すぎる場合、ファイルではなく指定します

Metrics/BlockLength:
  ExcludedMethods: ['describe', 'context']
80
J. Willette