Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Minitest:
Include:
- '**/test/**/*'
- '**/*_test.rb'
# Additional test base class names to recognize as test classes.
# Example: ['MyCustomBase', 'ApplicationTestCase']
AdditionalTestBaseClasses: []

Minitest/AssertEmpty:
Description: 'This cop enforces the test to use `assert_empty` instead of using `assert(object.empty?)`.'
Expand Down
25 changes: 23 additions & 2 deletions lib/rubocop/cop/mixin/minitest_exploration_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module RuboCop
module Cop
# Helper methods for different explorations against test files and test cases.
# @api private
module MinitestExplorationHelpers
module MinitestExplorationHelpers # rubocop:disable Metrics/ModuleLength
include DefNode
extend NodePattern::Macros

Expand Down Expand Up @@ -40,8 +40,29 @@ module MinitestExplorationHelpers

private

def additional_test_base_classes
return [] unless respond_to?(:cop_config)

cop_config.fetch('AdditionalTestBaseClasses', [])
rescue StandardError
[]
end

def test_base_classes
default_base_classes = %w[
Minitest::Test
ActiveSupport::TestCase
ActionController::TestCase
ActionDispatch::IntegrationTest
]

default_base_classes + additional_test_base_classes
end

def test_class?(class_node)
class_node.parent_class && class_node.identifier.source.end_with?('Test')
return false unless class_node.parent_class

test_base_classes.include?(class_node.parent_class.source)
end

def test_case?(node)
Expand Down
12 changes: 11 additions & 1 deletion test/rubocop/cop/minitest/duplicate_test_run_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
require_relative '../../../test_helper'

class DuplicateTestRunTest < Minitest::Test
def config
RuboCop::Config.new('Minitest' => { 'AdditionalTestBaseClasses' => ['ParentTest'] })
end

def test_registers_offense_when_parent_and_child_have_tests_methods
assert_offense(<<~RUBY)
class ParentTest < Minitest::Test
Expand Down Expand Up @@ -89,7 +93,11 @@ class ClassTwo < ParentTest
end

def test_does_not_register_offense_if_the_class_is_not_a_test_class
assert_no_offenses(<<~RUBY)
# Use a cop without ParentTest in AdditionalTestBaseClasses
cop_config = RuboCop::Config.new('Minitest' => { 'AdditionalTestBaseClasses' => [] })
cop_instance = RuboCop::Cop::Minitest::DuplicateTestRun.new(cop_config)

offenses = inspect_source(<<~RUBY, cop_instance)
class ParentTest < ExampleClass
def test_child_asserts_twice
assert_equal(1, 1)
Expand All @@ -102,6 +110,8 @@ def test_child_asserts_twice
end
end
RUBY

assert_empty offenses
end

def test_does_not_throw_error_if_missing_parent_test_class
Expand Down
29 changes: 29 additions & 0 deletions test/rubocop/cop/minitest/no_test_cases_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,33 @@ def perform; end
end
RUBY
end

def test_does_not_register_offense_for_non_test_parent_class
assert_no_offenses(<<~RUBY)
class FooTest < ApplicationRecord
def perform; end
end
RUBY
end

def test_registers_offense_with_additional_test_base_classes_configuration
cop_config = RuboCop::Config.new('Minitest/NoTestCases' => { 'AdditionalTestBaseClasses' => ['MyCustomBase'] })
cop_instance = RuboCop::Cop::Minitest::NoTestCases.new(cop_config)

offenses = inspect_source(<<~RUBY, cop_instance)
class FooTest < MyCustomBase
end
RUBY

assert_equal 1, offenses.size
assert_equal 'Test class should have test cases.', offenses.first.message
end

def test_does_not_register_offense_without_additional_test_base_classes_configuration
assert_no_offenses(<<~RUBY)
class FooTest < MyCustomBase
def perform; end
end
RUBY
end
end
54 changes: 53 additions & 1 deletion test/rubocop/cop/mixin/minitest_exploration_helpers_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Helper
extend RuboCop::Cop::MinitestExplorationHelpers

class << self
public :test_case?
public :test_case?, :test_class?, :test_base_classes
end
end

Expand Down Expand Up @@ -42,6 +42,58 @@ def test_test_case_returns_false_for_test_methods_with_arguments
refute Helper.test_case?(method_node(:test_with_arguments))
end

# Tests for test_class? method
def test_test_class_returns_true_for_minitest_test
source = 'class FooTest < Minitest::Test; end'
assert Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_true_regardless_of_class_name
source = 'class Foo < Minitest::Test; end'
assert Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_false_for_non_test_parent
source = 'class FooTest < ApplicationRecord; end'
refute Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_true_for_activesupport_testcase
source = 'class FooTest < ActiveSupport::TestCase; end'
assert Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_true_for_actioncontroller_testcase
source = 'class MyController < ActionController::TestCase; end'
assert Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_true_for_actiondispatch_integrationtest
source = 'class MyIntegration < ActionDispatch::IntegrationTest; end'
assert Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_false_without_parent_class
source = 'class FooTest; end'
refute Helper.test_class?(parse_source!(source).ast)
end

def test_test_class_returns_false_for_unknown_parent
source = 'class TestHelper < ActionMailer::Base; end'
refute Helper.test_class?(parse_source!(source).ast)
end

def test_test_base_classes_contains_default_classes
expected_classes = %w[
Minitest::Test
ActiveSupport::TestCase
ActionController::TestCase
ActionDispatch::IntegrationTest
]

assert_equal expected_classes, Helper.test_base_classes
end

private

def method_node(method_name)
Expand Down