RuboCop-RSpec のバージョン 1.16.0 がリリースされました。
https://github.com/backus/rubocop-rspec/releases/tag/v1.16.0
RuboCop-RSpec とは、RSpec 特有の問題を RuboCop で検知するためのプラグインです。
CHANGELOG から、新規追加の Cop を見ていこうと思います。
FactoryGirl/DynamicAttributeDefinedStatically
FactoryGirl では、アトリビュートの値を動的に定義することが出来ます。
FactoryGirl.define do factory :user do name { ['a', 'b', 'c'].sample } end end user1 = FactoryGirl.create :user user1.name # => 'c' user2 = FactoryGirl.create :user user2.name # => 'b'
このように、ブロックをつかうことで動的にアトリビュートを定義することが出来ます。
この Cop は、動的に定義するつもりのアトリビュートが静的に定義されていた場合警告を出します。
例:
FactoryGirl.define do factory :user do # ブロックが無いため、`sample`は定義時に実行されてしまう name ['a', 'b', 'c'].sample end end # 何度実行しても name は同じ user1 = FactoryGirl.create :user user1.name # => 'a' user2 = FactoryGirl.create :user user2.name # => 'a'
RSpec/AlignLeftLetBrace, RSpec/AlignRightLetBrace
この Cop は、let
を定義する際に左右の括弧が揃っているかどうかを検証します。
# RSpec/AlignLeftLetBrace は警告を出す。 let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } # こう直す let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b }
# RSpec/AlignRightLetBrace は警告を出す。 let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } # こう直す let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b }
なお、このCopはデフォルトでは無効になっています。
そのため、有効にするには明示的に.rubocop.yml
で指定する必要があります。
RSpec/AlignLeftLetBrace: Enabled: true RSpec/AlignRightLetBrace: Enabled: true
RSpec/LetBeforeExamples
この Cop は、let
の定義がit
よりも前にあるべきであることを検査します。
describe 'let が it の後にあるので警告が出る' do it 'something' do end let(:foo) { 'foo' } end describe 'let が it の前にあるので問題ない' do let(:foo) { 'foo' } it 'something' do end end
RSpec/MultipleSubjects
この Cop はsubject
が複数ある場合に警告を出します。
RSpec では subject が複数定義されていた場合、最後に定義された subject が subject として参照できます。 また、名前付き subject である場合はその名前で参照することが出来ますが、subject である必要はないでしょう。
そのため、一つのdescribeのスコープ内で定義される subject はひとつであるべきです。
例:
describe Foo do subject(:user) { User.new } # user としてのみアクセスできる subject { dead_code } # アクセスできない subject(:post) { Post.new } # subject, post としてアクセスできる end
RSpec/ReturnFromStub
この Cop は、戻り値を返すstubを定義する時に使うスタイルを統一します。
stub から戻り値を返すには、二つの方法があります。
allow(foo).to receive(:bar).and_return('baz') allow(foo).to receive(:bar) { 'baz' }
この Cop はデフォルトではand_return
を使用するように指摘します(つまり、ブロックを使っていた場合警告されます)。
この挙動は、.rubocop.yml
で変更することができます。
# `and_return`の使用を強制したい場合(default) RSpec/ReturnFromStub: EnforcedStyle: and_return # ブロックの使用を強制したい場合 RSpec/ReturnFromStub: EnforcedStyle: block
RSpec/VoidExpect
RSpec では、以下のように空のexpect
が書かれていても、何も検査されません。
it do # 何も検査しないが、エラーにはならない expect(something) end
この Cop は、上記のようなコードに対して警告を追加します。
RSpec/InvalidPredicateMatcher
RSpec では、以下のようにして predicate method (メソッド名が?
で終わるメソッド)に対応するマッチャーを呼び出すことが出来ます。
it do # expect('str'.start_with?('s')).to be_truthy と同じ expect('str').to be_start_with('s') end
ですが、人間は?
をつけたくなってしまいます。つまり、以下のような間違いを犯してしまいます。
it do expect('str').to be_start_with?('s') # ^ この ? は要らない end
この Cop は上記のような間違いを指摘します。
この余分な?
は実際にRSpecを実行した場合もエラーになりますが、そのエラーメッセージは若干分かりづらいです。
expected "str" to respond to `star_with??`
この Cop を使用することでより良いメッセージを手に入れることが出来ます。
RSpec/PredicateMatcher
前述した通り、RSpecには predicate method をマッチャーとして呼び出すことができます。
この Cop は、predicate method をマッチャーとして呼び出せるのにbe_truthy
を使っている場合を検出します。
it do # これは be_start_with matcher を使用できる。 expect('str'.start_with?('s')).to be_truthy # こう書いた方がスマート expect('str').to be_start_with('s') end
なお、.rubocop.yml
で設定をすることで、be_truthy
を使うような形を強制することも出来ます。
# `expect('str'.start_with?('s')).to be_truthy` と書きたい場合 RSpec/PredicateMatcher: EnforcedStyle: explicit
また、この Cop にはStrict
オプションも存在します。
これはデフォルトではtrue
になっていますが、false
にすることで厳密にはpredicate matcherでは置き換えられないものに対しても警告を出すようになります。
RSpec/PredicateMatcher: Strict: false
it do # これはだいたいの場合に置いて be_start_with matcher を使用できる expect('str'.start_with?('s')).to be true end
Strict: false
によって、be_truthy
以外にもbe true
やeq true
を使用している場合にも警告を与えるようになります。
be_truthy
と違いbe true
を使用している場合、そのテストは「trueとして評価される値を返す」ことを期待しているのではなく、「厳密にtrueを返す」ことを期待しているテストである可能性があります。
そのため、be true
は必ずしもpredicate matcherで置き換えられるとは限りません。
ただし、「厳密にtrueを返す」ことを期待するようなテストを書きたいのはライブラリを作っている場合などに限られると思います。
そのため、Rails applicationなどではStrict: false
にして運用してもほとんど問題はないでしょう。
RSpec/ExpectInHook
RSpec では、before
やafter
などのhookと、it
の中で行えることは同じです。
そのため、before
の中でexpect
を書いてしまっても特に問題なく動きます。
describe do before do # before の中で expect は動く expect(something).to eq 1 end it do # ... end end
ですが、expect
はbefore
ではなく、it
の中に書かれるべきです。
この Cop は、上記のように it 以外のところに書かれたexpect
に対して警告を出します。
まとめ
RuboCop-RSpec 1.16.0 で追加された Cop は以上になります。 これを気に RuboCop-RSpec を導入してみてはいかがでしょうか?