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:
https://relishapp.com/rspec/rspec-core/v/3-8/docs/subject/implicitly-defined-subject> If the first argument to the outermost example group is a class, an instance of that class is exposed to each example via the subject method.
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.