RuboCopにRSpecのルールが提供されているので導入してみました。
RSpecのルールはデフォルトだと厳し過ぎるのと、あえて従いたくないルールもあるので設定変更しました。今まで書いていたものも、自分なりのルールで書いているので、極力修正不要なように。
可読性は大事だけど、lint通す為に時間を掛け過ぎても、本来実現したいデリバリーを早くする事が難しくなるので。
RuboCop RSpec :: RuboCop Docs
参考: 既存のルール調整
先に既存のルールを調整したので、参考までに記載しておきます。
.rubocop.yml
inherit_from: .rubocop_todo.yml
AllCops:
NewCops: enable
SuggestExtensions: false
Exclude:
- 'bin/*'
- 'db/schema.rb'
- 'node_modules/**/*'
### Layout
# https://docs.rubocop.org/rubocop/cops_layout.html
# C: Layout/LineLength: Line is too long.
Layout/LineLength:
Max: 160
### Metrics
# https://docs.rubocop.org/rubocop/cops_metrics.html
# C: Metrics/AbcSize: Assignment Branch Condition size for expect_space_json is too high.
Metrics/AbcSize:
Exclude:
- 'spec/**/*'
# C: Metrics/BlockLength: Block has too many lines.
Metrics/BlockLength:
Exclude:
- 'app/views/**/*.jbuilder'
- 'config/environments/*'
- 'config/routes.rb'
- 'config/routes/*'
- 'lib/tasks/**/*'
- 'spec/**/*'
# C: Metrics/ClassLength: Class has too many lines.
Metrics/ClassLength:
Enabled: false
# C: Metrics/MethodLength: Method has too many lines.
Metrics/MethodLength:
Max: 30
Exclude:
- 'db/migrate/*'
- 'spec/**/*'
# C: Metrics/ModuleLength: Module has too many lines.
Metrics/ModuleLength:
Enabled: false
# C: Metrics/ParameterLists: Avoid parameter lists longer than 5 parameters.
Metrics/ParameterLists:
Exclude:
- 'spec/**/*'
### Naming
# https://docs.rubocop.org/rubocop/cops_naming.html
# C: Naming/AccessorMethodName: Do not prefix writer method names with set_.
Naming/AccessorMethodName:
Enabled: false
# C: Naming/VariableNumber: Use normalcase for method name numbers.
Naming/VariableNumber:
Exclude:
- 'spec/**/*'
### Style
# https://docs.rubocop.org/rubocop/cops_style.html
# C: Style/AsciiComments: Use only ascii symbols in comments.
Style/AsciiComments:
Enabled: false
# C: [Correctable] Style/BlockComments: Do not use block comments.
Style/BlockComments:
Enabled: false
# C: Style/ClassAndModuleChildren: Use nested module/class definitions instead of compact style.
Style/ClassAndModuleChildren:
Enabled: false
# C: [Correctable] Style/ConditionalAssignment: Use the return of the conditional for variable assignment and comparison.
Style/ConditionalAssignment:
Enabled: false
# C: Style/Documentation: Missing top-level class documentation comment.
Style/Documentation:
Enabled: false
# C: [Correctable] Style/DoubleNegation: Avoid the use of double negation (!!).
Style/DoubleNegation:
Enabled: false
# C: Style/FormatStringToken: Prefer annotated tokens (like %s) over unannotated tokens (like %s).
Style/FormatStringToken:
Enabled: false
# C: Style/FrozenStringLiteralComment: Missing frozen string literal comment.
Style/FrozenStringLiteralComment:
Enabled: false
# C: Style/GuardClause: Use a guard clause (*) instead of wrapping the code inside a conditional expression.
Style/GuardClause:
Enabled: false
# C: [Corrected] Style/IfInsideElse: Convert if nested inside else to elsif.
Style/IfInsideElse:
Enabled: false
# C: [Corrected] Style/Lambda: Use the -> { ... } lambda literal syntax for all lambdas.
Style/Lambda:
EnforcedStyle: literal
# C: [Corrected] Style/NumericLiterals: Use underscores(_) as thousands separator and separate every 3 digits with them.
Style/NumericLiterals:
MinDigits: 7
# C: [Correctable] Style/NumericPredicate: Use xxx.positive?/zero? instead of xxx > 0/== 0.
Style/NumericPredicate:
Enabled: false
# C: Style/OptionalBooleanParameter: Use keyword arguments when defining method with boolean argument.
Style/OptionalBooleanParameter:
Enabled: false
rubocop-rspecインストール
Gemfile
group :development, :test do
# Use RuboCop
gem 'rubocop'
gem 'rubocop-rails'
+ gem 'rubocop-rspec'
% bundle install
.rubocop.yml
### RSpec
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html
require: rubocop-rspec
RSpec:
Enabled: true
RSpecのルール変更
rubocopコマンドの実行とルールの追加 or 修正を通るまで、繰り返しました。
無効にしたルール
.rubocop.yml
# C: RSpec/ContextWording: Context description should match /^when\b/, /^with\b/, or /^without\b/.
RSpec/ContextWording:
Enabled: false
# C: RSpec/DescribeSymbol: Avoid describing symbols.
RSpec/DescribeSymbol:
Enabled: false
# C: [Correctable] RSpec/EmptyLineAfterExample: Add an empty line after it.
RSpec/EmptyLineAfterExample:
Enabled: false
# C: [Correctable] RSpec/EmptyLineAfterExampleGroup: Add an empty line after shared_examples_for.
RSpec/EmptyLineAfterExampleGroup:
Enabled: false
# C: [Correctable] RSpec/EmptyLineAfterFinalLet: Add an empty line after the last let.
RSpec/EmptyLineAfterFinalLet:
Enabled: false
# C: [Correctable] RSpec/EmptyLineAfterHook: Add an empty line after before.
RSpec/EmptyLineAfterHook:
Enabled: false
# C: [Corrected] RSpec/EmptyLineAfterSubject: Add an empty line after subject.
RSpec/EmptyLineAfterSubject:
Enabled: false
# C: RSpec/ExampleLength: Example has too many lines.
RSpec/ExampleLength:
Enabled: false
# C: RSpec/ExpectInLet: Do not use expect in let
RSpec/ExpectInLet:
Enabled: false
# C: [Corrected] RSpec/ImplicitSubject: Don't use implicit subject.
RSpec/ImplicitSubject:
Enabled: false
# C: RSpec/InstanceVariable: Avoid instance variables - use let, a method call, or a local variable (if possible).
RSpec/InstanceVariable:
Enabled: false
# C: RSpec/MissingExampleGroupArgument: The first argument to context should not be empty.
RSpec/MissingExampleGroupArgument:
Enabled: false
# C: RSpec/MultipleExpectations: Example has too many expectations
RSpec/MultipleExpectations:
Enabled: false
# C: RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers
RSpec/MultipleMemoizedHelpers:
Enabled: false
# C: RSpec/NestedGroups: Maximum example group nesting exceeded
RSpec/NestedGroups:
Enabled: false
# C: RSpec/RepeatedExampleGroupBody: Repeated context block body on line(s)
RSpec/RepeatedExampleGroupBody:
Enabled: false
# C: RSpec/RepeatedExampleGroupDescription: Repeated context block description on line(s)
RSpec/RepeatedExampleGroupDescription:
Enabled: false
# C: [Correctable] RSpec/ScatteredLet: Group all let/let! blocks in the example group together.
RSpec/ScatteredLet:
Enabled: false
対応したルール
RSpec/BeEq
C: [Correctable] RSpec/BeEq: Prefer be over eq.
spec/lib/tasks/user/destroy_spec.rb
- expect(User.exists?(id: users)).to eq(false)
+ expect(User.exists?(id: users)).to be(false)
※be_falsey
を使わないのは、nil
でもパスしてしまう為。
RSpec/NoExpectationExample
spec/routing/infomations_routing_spec.rb
C: RSpec/NoExpectationExample: No expectation found in this example.
spec/lib/tasks/all/destroy_spec.rb
it '正常終了' do
- subject
+ expect { subject }.not_to raise_error
end
spec/routing/infomations_routing_spec.rb
- it 'routes to #new' do
- # expect(get: '/infomations/new').not_to be_routable # NOTE: infomations#show
- end
+ # it 'routes to #new' do
+ # expect(get: '/infomations/new').not_to be_routable # NOTE: infomations#show
+ # end
RSpec/ReceiveMessages
C: [Correctable] RSpec/ReceiveMessages: Use receive_messages instead of multiple stubs on lines
spec/helpers/application_helper_spec.rb
- before do
- allow(helper).to receive(:controller_name).and_return(controller_name)
- allow(helper).to receive(:action_name).and_return(action_name)
- end
+ before { allow(helper).to receive_messages(controller_name:, action_name:) }
RSpec/ChangeByZero
C: [Correctable] RSpec/ChangeByZero: Prefer not_to change over to change.by(0).
spec/requests/users/auth/registrations_spec.rb
- expect { subject }.to change(User, :count).by(0) && change(ActionMailer::Base.deliveries, :count).by(0)
+ expect { subject }.not_to change(User, :count) && change(ActionMailer::Base.deliveries, :count)
RSpec/HookArgument
C: [Correctable] RSpec/HookArgument: Omit the default :each argument for RSpec hooks.
spec/rake_helper.rb
- config.before(:each) do
+ config.before do
RSpec/DescribedClass
C: [Correctable] RSpec/DescribedClass: Use described_class instead of xxx.
spec/models/user_spec.rb
- let(:current_user) { User.find(user.id) }
+ let(:current_user) { described_class.find(user.id) }
追加修正
let(:model) → subject(:model)
spec/models/user_spec.rb
- let(:model) { FactoryBot.build_stubbed(:user, code:) }
+ subject(:model) { FactoryBot.build_stubbed(:user, code:) }
let(:mail) → subject(:mail)
spec/mailers/user_mailer_spec.rb
- let(:mail) { UserMailer.with(user:).destroy_reserved }
+ subject(:mail) { described_class.with(user:).destroy_reserved }
subject do → subject {
好みもあるけど、4行が2行、5行が3行になるのと、見やすいかも。
spec/requests/users/auth/confirmations_spec.rb
- subject do
- headers = auth_headers.merge(accept_headers)
- get user_auth_confirmation_path(format: subject_format, confirmation_token:, redirect_url: @redirect_url), headers:
- end
+ subject { get user_auth_confirmation_path(format: subject_format, confirmation_token:, redirect_url: @redirect_url), headers: }
+ let(:headers) { auth_headers.merge(accept_headers) }
spec/helpers/application_helper_spec.rb
- subject do
- FactoryBot.create_list(:user, count)
- models = User.page(page).per(2)
- helper.first_page_number(models)
- end
+ subject { helper.first_page_number(models) }
+ before { FactoryBot.create_list(:user, count) }
+ let(:models) { User.page(page).per(2) }
spec/models/user_spec.rb
- subject do
- user.cache_infomation_unread_count = nil
- user.infomation_unread_count
- end
+ subject { user.infomation_unread_count }
+ before { user.cache_infomation_unread_count = nil }