diff --git a/CHANGELOG.md b/CHANGELOG.md index ce02b9191..bf7da8d31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Recognize stubbing of `described_class` in `RSpec/SubjectStub`. ([@lovro-bikic]) + ## 3.6.0 (2025-04-18) - Fix false positive in `RSpec/Pending`, where it would mark the default block `it` as an offense. ([@bquorning]) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 635e6657d..01f7ecc6d 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -6096,6 +6096,16 @@ describe Article do end end +# bad - described_class stubs are recognized as well +describe Article do + it 'indicates that the author is unknown' do + article = double(Article, description: 'by an unknown author') + allow(described_class).to receive(:new).and_return(article) + + expect(Article.new.description).to include('by an unknown author') + end +end + # good describe Article do subject(:article) { Article.new(author: nil) } diff --git a/lib/rubocop/cop/rspec/subject_stub.rb b/lib/rubocop/cop/rspec/subject_stub.rb index 273e4fea9..41d669cc2 100644 --- a/lib/rubocop/cop/rspec/subject_stub.rb +++ b/lib/rubocop/cop/rspec/subject_stub.rb @@ -38,6 +38,16 @@ module RSpec # end # end # + # # bad - described_class stubs are recognized as well + # describe Article do + # it 'indicates that the author is unknown' do + # article = double(Article, description: 'by an unknown author') + # allow(described_class).to receive(:new).and_return(article) + # + # expect(Article.new.description).to include('by an unknown author') + # end + # end + # # # good # describe Article do # subject(:article) { Article.new(author: nil) } @@ -141,7 +151,7 @@ def find_subject_expectations(node, subject_names = [], &block) subject_names = [*subject_names, *@explicit_subjects[node]] subject_names -= @subject_overrides[node] if @subject_overrides[node] - names = Set[*subject_names, :subject] + names = Set[*subject_names, :subject, :described_class] expectation_detected = message_expectation?(node, names) return yield(node) if expectation_detected diff --git a/spec/rubocop/cop/rspec/subject_stub_spec.rb b/spec/rubocop/cop/rspec/subject_stub_spec.rb index 575f27f76..2c48fc802 100644 --- a/spec/rubocop/cop/rspec/subject_stub_spec.rb +++ b/spec/rubocop/cop/rspec/subject_stub_spec.rb @@ -364,6 +364,17 @@ RUBY end + it 'flags when described_class is mocked' do + expect_offense(<<~RUBY) + describe Foo do + it 'uses described_class' do + expect(described_class).to receive(:bar).and_return(baz) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not stub methods of the object under test. + end + end + RUBY + end + it 'flags when there are several top level example groups' do expect_offense(<<~RUBY) RSpec.describe Foo do