Skip to content

Commit

Permalink
Add new Rails/ActionControllerTesting cop
Browse files Browse the repository at this point in the history
Add controller testing cop to discourage use of
ActionController::TestCase. ActionDispatch::IntegrationTest should be
used instead to test controllers.
  • Loading branch information
gmcgibbon committed Feb 7, 2022
1 parent 73b6947 commit b33f717
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/new_rails_action_controller_testing_cop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#638](https://github.com/rubocop/rubocop-rails/pull/638): Add new `Rails/ActionControllerTesting` cop. ([@gmcgibbon][])
10 changes: 10 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ Lint/NumberConversion:
- fortnights
- in_milliseconds

Rails/ActionControllerTesting:
Description: 'Use `ActionDispatch::IntegrationTest` instead of `ActionController::TestCase`.'
Reference: 'https://api.rubyonrails.org/classes/ActionController/TestCase.html'
StyleGuide: 'https://rails.rubystyle.guide/#integration-testing'
Enabled: true
SafeAutocorrect: false
VersionAdded: '<<next>>'
Include:
- '**/test/**/*.rb'

Rails/ActionFilter:
Description: 'Enforces consistent use of action filter methods.'
Enabled: true
Expand Down
47 changes: 47 additions & 0 deletions lib/rubocop/cop/rails/action_controller_testing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
# Using ActionController::TestCase is discouraged and should be replaced by
# ActionDispatch::IntegrationTest. Controller tests are too close to the
# internals of a controller whereas integration tests mimic the browser/user.
#
# @safety
# This cop's autocorrection is unsafe because the API of each test case class is different.
# Make sure to update each test of your controller test cases after changing the superclass.
#
# @example
# # bad
# class MyControllerTest < ActionController::TestCase
# end
#
# # good
# class MyControllerTest < ActionDispatch::IntegrationTest
# end
#
class ActionControllerTesting < Base
extend AutoCorrector
extend TargetRailsVersion

MSG = 'Use `ActionDispatch::IntegrationTest` instead.'

minimum_target_rails_version 5.0

def_node_matcher :controller_test_case?, <<~PATTERN
(class
(const nil? _)
(const (const _ :ActionController) :TestCase) nil?)
PATTERN

def on_class(node)
return unless controller_test_case?(node)

add_offense(node.parent_class) do |corrector|
corrector.replace(node.parent_class, 'ActionDispatch::IntegrationTest')
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rails_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require_relative 'mixin/migrations_helper'
require_relative 'mixin/target_rails_version'

require_relative 'rails/action_controller_testing'
require_relative 'rails/action_filter'
require_relative 'rails/active_record_aliases'
require_relative 'rails/active_record_callbacks_order'
Expand Down
52 changes: 52 additions & 0 deletions spec/rubocop/cop/rails/action_controller_testing_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::ActionControllerTesting, :config do
context 'Rails 4.2', :rails42, :config do
it 'does not add offense when extending ActionController::TestCase' do
expect_no_offenses(<<~RUBY)
class MyControllerTest < ActionController::TestCase
end
RUBY
end
end

it 'adds offense when extending ActionController::TestCase' do
expect_offense(<<~RUBY)
class MyControllerTest < ActionController::TestCase
^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `ActionDispatch::IntegrationTest` instead.
end
RUBY

expect_correction(<<~RUBY)
class MyControllerTest < ActionDispatch::IntegrationTest
end
RUBY
end

it 'adds offense when extending ::ActionController::TestCase' do
expect_offense(<<~RUBY)
class MyControllerTest < ::ActionController::TestCase
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `ActionDispatch::IntegrationTest` instead.
end
RUBY

expect_correction(<<~RUBY)
class MyControllerTest < ActionDispatch::IntegrationTest
end
RUBY
end

it 'does not add offense when extending ActionDispatch::IntegrationTest' do
expect_no_offenses(<<~RUBY)
class MyControllerTest < ActionDispatch::IntegrationTest
end
RUBY
end

it 'does not add offense when extending custom superclass' do
expect_no_offenses(<<~RUBY)
class MyControllerTest < SuperControllerTest
end
RUBY
end
end

0 comments on commit b33f717

Please sign in to comment.