New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Difference between subject and let #6
Comments
class SomeClass
def some_method
puts "hello"
end
end
instance_of_some_class = SomeClass.new
instance_of_some_class.some_method #=> returns puts "hello"
#using subject to write this test
describe SomeClass do
describe 'some_method' do
it 'prints out hello' do
expect(subject.some_method).to eq("hello")
end
end
end
describe 'SomeClass' do
before do
@subject = SomeClass.new #=> create a new instance of the class for the thing under test
end
describe 'some_method' do
it 'prints out hello' do
expect(@subject.some_method).to eq("hello")
end
end
end
let(:radical) { "totally radical" }
# I think it is the same code wise as:
def radical
return @radical ||= "totally radical"
end This part of better spec helped me understand it. @odigity does that help you? There is more going on in RSpec but this is basically how I think about it right now. I'm going to close this because this isn't information we would add to this style guide, but thanks for asking this question! 🤘 |
Two things I found online that may help clear it up as well:
One thing I ran across while researching this question, that we may want to consider adding to this style guide: "Named Subjects" subject(:account) { CheckingAccount.new(Money.new(50, :USD)) } I find that Sources: |
I see that they're intended to be used for two different (but similar) concepts, but in implementaiton, they seem identical, and therefore, practically interchangeable. Both created named helper methods that return the result of evaluating a block, which is memoized for each example: subject(:foo) { MyClass.new } -> expect(foo).to be_whatever And it doesn't matter that one of them was declared with subject and one with let, because you end up with the same result, and use it the same way. The one exception is with the is_expected.to shortcut, which implictly uses the value of subject(). But once you consider the best practice of only using named subjects, even that diffference disappears. Hence my confusion. |
@odigity if you look at the example over at the link I posted: http://benscheirman.com/2011/05/dry-up-your-rspec-files-with-subject-let-blocks/ You can use the subject (or named subject) to be the class you are testing against and use the "lets" as a way to change the context in each test, as lets are not actually rendered (created in a sense) until they are called (used). Example given in the above link (with minor addition): #improved example
require 'spec_helper'
describe Card do
subject do
Card.new(card_type)
end
describe "#value" do
context "Two of Hearts" do
let(:card_type) { "2H" }
its(:value) { should == 2 }
# or
expect(subject.value).to eq(2)
end
end
end |
But wouldn't the exact opposite work just as well, other than going against the "intention" of the use of the two helpers? describe Card do (I know the language is the opposite of what's intended, but I'm just trying to understand the actual difference in implementation right now... and there doesn't seem to be any...) |
The thing with I agree, they have similarities under the hood because it's really just ruby, but their intended use is different. Just incase someone wants to read the docs in the future: |
So far we haven't disagreed, which makes me think maybe I'm failing to get my point across.
The same is true of subject().
The same is true of subject().
I specifically pointed that out already as the only thing I know of that makes subject different than let. However, that only works with unnamed subjects, which the RSpec docs specifically recommend against. They recommend named subjects:
In which case you could swap out subject for let without changing anything else:
So, again -- what is the actual difference between the two? Does it just come down to a convention of choosing a primary object (the object being tested), using subject for that, and then using let for any other state you may want to create a helper for? |
If I could chime in and hopefully say something that hasn't yet been said... the only real difference(s) I know of are:
context "when something" do
subject(:car) { FactoryGirl.create(:car) }
it { is_expected.to_not be_running }
end Once again, I hope I contribute to the solution - instead of sparking more conflict. |
I think that perfectly sums it up. It should additionally be noted that as far as I can tell, you can use the subject in a let block, or a previously defined let in the subject block, since both are only invoked when you invoke them, so there's no real ordering rule, right? |
I've spent the last half hour trying to google the difference between subject and let, after having already read the RSpec docs, which is how I came across this guide. Which I'm thankfully for, because there's lots of useful suggestions here.
However, when I finally got to the subject/lets section, my excitement turned to disappointment. I still don't understand the difference between subject and let...
Help?
The text was updated successfully, but these errors were encountered: