-
-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolves #279. This PR adds new `Minitest/NonExecutableTestMethod` cop, which checks for the use of test methods outside of a test class. Test methods should be defined within a test class to ensure their execution. NOTE: This cop assumes that classes whose superclass name includes the word "`Test`" are test classes, in order to prevent false positives. ```ruby # bad class FooTest < Minitest::Test end def test_method_should_be_inside_test_class end # good class FooTest < Minitest::Test def test_method_should_be_inside_test_class end end ```
- Loading branch information
Showing
4 changed files
with
216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Minitest | ||
# Checks for the use of test methods outside of a test class. | ||
# | ||
# Test methods should be defined within a test class to ensure their execution. | ||
# | ||
# NOTE: This cop assumes that classes whose superclass name includes the word | ||
# "`Test`" are test classes, in order to prevent false positives. | ||
# | ||
# @example | ||
# | ||
# # bad | ||
# class FooTest < Minitest::Test | ||
# end | ||
# def test_method_should_be_inside_test_class | ||
# end | ||
# | ||
# # good | ||
# class FooTest < Minitest::Test | ||
# def test_method_should_be_inside_test_class | ||
# end | ||
# end | ||
# | ||
class NonExecutableTestMethod < Base | ||
include MinitestExplorationHelpers | ||
|
||
MSG = 'Test method should be defined inside a test class to ensure execution.' | ||
|
||
def on_def(node) | ||
return if !test_method?(node) || !use_test_class? | ||
return if node.left_siblings.none? { |sibling| possible_test_class?(sibling) } | ||
|
||
add_offense(node) | ||
end | ||
|
||
def use_test_class? | ||
root_node = processed_source.ast | ||
|
||
root_node.each_descendant(:class).any? { |class_node| test_class?(class_node) } | ||
end | ||
|
||
def possible_test_class?(node) | ||
node.is_a?(AST::ClassNode) && test_class?(node) && node.parent_class.source.include?('Test') | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
158 changes: 158 additions & 0 deletions
158
test/rubocop/cop/minitest/non_executable_test_method_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative '../../../test_helper' | ||
|
||
class NonExecutableTestMethodTest < Minitest::Test | ||
def test_registers_offense_when_test_method_is_defined_outside_minitest_test_class | ||
assert_offense(<<~RUBY) | ||
class FooTest < Minitest::Test | ||
end | ||
def test_foo | ||
^^^^^^^^^^^^ Test method should be defined inside a test class to ensure execution. | ||
end | ||
RUBY | ||
end | ||
|
||
def test_registers_offense_when_test_method_is_defined_outside_active_support_test_case_class | ||
assert_offense(<<~RUBY) | ||
class FooTest < ActiveSupport::TestCase | ||
end | ||
def test_foo | ||
^^^^^^^^^^^^ Test method should be defined inside a test class to ensure execution. | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_method_is_defined_outside_namespaced_test_class | ||
assert_offense(<<~RUBY) | ||
module M | ||
class FooTest < Minitest::Test | ||
def test_foo | ||
end | ||
end | ||
def test_bar | ||
^^^^^^^^^^^^ Test method should be defined inside a test class to ensure execution. | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_non_test_method_is_defined_outside_test_class | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < Minitest::Test | ||
end | ||
def do_something | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_non_test_method_is_defined_outside_active_support_test_case_class | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < ActiveSupport::TestCase | ||
end | ||
def do_something | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_method_is_defined_inside_test_class | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < Minitest::Test | ||
def test_foo | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_method_is_defined_inside_test_helper_class | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < Minitest::Test | ||
def test_foo | ||
end | ||
end | ||
class TestHelperMailer < ActionMailer::Base | ||
def test_parameter_args | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_method_is_defined_inside_test_helper_module | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < Minitest::Test | ||
def test_foo | ||
end | ||
end | ||
module TestHelper | ||
def test_parameter_args | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_class_in_which_test_method_is_defined_is_repeated | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < Minitest::Test | ||
def test_foo | ||
end | ||
end | ||
class FooTest < Minitest::Test | ||
def test_foo | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_method_is_defined_and_test_class_is_not_defined | ||
assert_no_offenses(<<~RUBY) | ||
def test_something | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_test_method_is_defined_inside_condition | ||
assert_no_offenses(<<~RUBY) | ||
module ActiveRecord | ||
class AdapterTest < ActiveRecord::TestCase | ||
unless current_adapter?(:PostgreSQLAdapter) | ||
def test_update_prepared_statement | ||
end | ||
end | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_nested_test_method_and_two_test_classes_are_defined | ||
assert_no_offenses(<<~RUBY) | ||
class FooTest < ActiveRecord::TestCase | ||
def test_foo | ||
def test_bar | ||
end | ||
end | ||
end | ||
class BarTest < ActiveRecord::TestCase | ||
end | ||
RUBY | ||
end | ||
|
||
def test_does_not_register_offense_when_non_test_case_class_is_defined_before_test_method | ||
assert_no_offenses(<<~RUBY) | ||
class SetTest < ActiveRecord::AbstractMysqlTestCase | ||
class SetTest < ActiveRecord::Base | ||
end | ||
def test_should_not_be_unsigned | ||
column = SetTest.columns_hash["set_column"] | ||
assert_not_predicate column, :unsigned? | ||
end | ||
end | ||
RUBY | ||
end | ||
end |