Hello A `subject` is just a special instance of `let`.
It is intended to give attention to the “subject” under test, originally it had some special powers as you note (such as the implicit subject, and chaining matchers of that as `is_expected.to matcher`) but those remain as syntactic sugar only really. We advocate that you at least name your subject (as you have), `subject(:person)` and then use it either implicitly (as `is_expected.to` or explicitly as its name, e.g. `expect(person).to`. Its value really depends on how you use it, as it is shared between various tests in a context, it should be the common value for that context. Personally I just use a let. Hope that helps. Jon Rowe --------------------------- [email protected] jonrowe.co.uk On 28 November 2018 at 16:32, Alexander Popov wrote: > Hello, > > Given a class: > > class Person > > def > name > > 'John' > > end > > > def > age > > 20 > > end > end > > > what is the proper way to use subject? > > Version 1: > > RSpec.describe Person do > > subject (:person) { Person.new } > > > it '#name' do > > expect (person.name).to eq 'John' > > end > > > it '#age' do > > expect (person.age).to eq 20 > > end > end > > Version 2: > > RSpec.describe Person do > > let (:person) { Person.new } > > > describe '#name' do > > subject { person.name } > > > it { is_expected.to eq 'John' } > > end > > > describe '#age' do > > subject { person.age } > > > it { is_expected.to eq 20 } > > end > end > > I think that most people have the very deeply-rooted belief that subject > necessarily needs to hold an instance of the class under test (Version 1). > This might partly come from this passage in the documentation: > > relishapp.com/rspec/rspec-core/v/3-8/docs/subject/implicitly-defined-subject > (https://relishapp.com/rspec/rspec-core/v/3-8/docs/subject/implicitly-defined-subject) > > > However, I think that here the documentation simply describes what the > default behavior is and doesn't imply that it always has to be that way. My > understanding is that subject conceptually represents the thing under > testing. If we want to assert the result of a method call, than subject > better hold this result. For example, again given a class: > > class Person > > attr_accessor : > name > > def initialize(name) > > @name = > name > > end > > > def > greeting > > "Hi, #{name}!" > > end > end > > I find it more appropriate to use subject like so: > > RSpec.describe Person do > > describe '#greeting' do > > context 'when the person is called John' do > > subject { Person.new('John').greeting } > > > it { is_expected.to eq 'Hi, John!' } > > end > > > context 'when the person is called Merry' do > > subject { Person.new('Merry').greeting } > > > it { is_expected.to eq 'Hi, Merry!' } > > end > > end > end > > instead of: > > RSpec.describe Person do > > subject (:person) { Person.new(name) } > > > describe '#greeting' do > > context 'when the person is called John' do > > let (:name) { 'John' } > > > it { expect(subject.greeting).to eq 'Hi, John!' } > > end > > > context 'when the person is called Merry' do > > let (:name) { 'Merry' } > > > it { expect(subject.greeting).to eq 'Hi, Merry!' } > > end > > end > end > > I'd like to know what is the recommended way of using subject. Thank you very > much. -- You received this message because you are subscribed to the Google Groups "rspec" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/dejalu-192-091d8894-a4a0-4fa5-91af-ebcee5f9a362%40jonrowe.co.uk. For more options, visit https://groups.google.com/d/optout.
