rubocop-rspec: RSpec/NamedSubject: false positive when raising error
Expected behavior
To not trigger when the following construction is used:
it { expect { subject }.to raise_error(ArgumentError, 'problem') }
Actual behavior
Suggests to name subject:
RSpec/NamedSubject: Name your test subject if you need to reference it explicitly.
it { expect { subject }.to raise_error(ArgumentError, 'problem') }
Steps to reproduce the problem
Enable RSpec/NamedSubject in your .rubocop.yml:
RSpec/NamedSubject:
Enabled: true
Add a spec that uses subject in a block to check for exception:
RSpec.describe Object do
subject { raise ArgumentError, 'problem' }
it { expect { subject }.to raise_error(ArgumentError, 'problem') }
end
RuboCop version
$ bundle exec rubocop -V
0.65.0 (using Parser 2.6.0.0, running on ruby 2.4.5 x86_64-darwin18)
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 16 (8 by maintainers)
I would agree with @bquorning that in general I expect
subjectto be an instance ofdescribed_class. As @mikegee suggests you could potentially have a#callcall in each example or something like that. I tend to think this is more clear and helpful.On some occasions when i’m testing a very imperative-feeling service object with a lot of setup, i might do something like this:
I find it personally a little odd to have a memoized subject helper represent a result or an action most of the time. If you’re testing a side effect through
subjectthat callingsubjecttwice wouldn’t cause the behavior twice (since it is memoized) so sometimes a plain old method feels more natural to me.That said, I think this is all a very grey area of testing. If you write a lot of tests that leave you fighting with this cop, disable it. Or disable it for a particular file. I think the expect block exception is probably too specific of a case to merit a special configuration option here, but I could possibly be convinced otherwise.
On a related note, I don’t use the implicit expect syntax at all because I prefer the expanded/explicit form but there are some testing situations where i could be convinced that it fits well.
This is a subjective cop and if you disagree with it that’s ok, but i wouldn’t consider this a false positive: it’s doing its job and asking you to use a descriptive subject name any time you want to explicitly reference your subject.
The RSpec cops live in the
rubocop-rspecproject. Please open up an issue in that project.Since opening this ticket I’ve been experimenting with naming and not naming subjects, my personal feeling is that I would rather not name it and use subject as my safe, go to name. For example, say I am writing tests for
NameImporterService, my subject isdescribed_class.new(dependency: dependency).call, should I name this subjectresult,call_result,names_count?In my opinion the extra clarity that a named subject could give in this situation defeats the mental energy required to think about a good name for it.
Nonetheless I understand how other people would like this rule and I have the option to disable it, so win/win for everyone. That’s the beauty of Rubocop, it’s extremely configurable, the cops have good SEOs and most of them have clear explanation why one style is preferred over another. ❤️
I would most often expect
subjectto be an instance ofdescribed_class; in your examples an instance ofUser.Following that pattern, calling
subjectshouldn’t have side effects, except perhaps storing a record in a database.I would recommend rewriting to e.g.:
Yes, this works as expected, I am just not sure what do I get from naming the subject in this case, it’s a short 2 line spec, it’s clear and no attributes are being read from the subject, for example:
vs
Is mentioning
subjectas a named variable a code smell or bad pattern in all scenarios?