-
-
Save dchelimsky/2244919 to your computer and use it in GitHub Desktop.
desc "A user's comment" do | |
let(:user) { User.create! name: "John" } | |
let(:comment) { user.comments.create! } | |
it "delegates to user's name" do | |
comment.name.should eq(user.name) | |
end | |
end |
desc "A user's comment" do | |
def user | |
@user ||= User.create! name: "John" | |
end | |
def comment | |
@comment ||= user.comments.create! | |
end | |
it "delegates to user's name" do | |
comment.name.should eq(user.name) | |
end | |
end |
desc "A user's comment" do | |
def user; @user ||= User.create! name: "John"; end | |
def comment; @comment ||= user.comments.create!; end | |
it "delegates to user's name" do | |
comment.name.should eq(user.name) | |
end | |
end |
# the original motivation for `let` was to make this scenario easier: | |
# step 1 | |
describe Thing do | |
it "does something" do | |
thing = Thing.new | |
thing.should do_something | |
end | |
end | |
# step 2 - add another example | |
describe Thing do | |
it "does something" do | |
thing = Thing.new | |
thing.should do_something | |
end | |
it "does something else" do | |
thing = Thing.new | |
thing.should do_something_else | |
end | |
end | |
# step 3 - refactor - without let | |
# 3a1 | |
describe Thing do | |
before do | |
@thing = Thing.new | |
end | |
it "does something" do | |
thing = Thing.new | |
thing.should do_something | |
end | |
it "does something else" do | |
thing = Thing.new | |
thing.should do_something_else | |
end | |
end | |
# 3a2 | |
describe Thing do | |
before do | |
@thing = Thing.new | |
end | |
it "does something" do | |
thing.should do_something | |
end | |
it "does something else" do | |
thing = Thing.new | |
thing.should do_something_else | |
end | |
end | |
# 3a3 | |
describe Thing do | |
before do | |
@thing = Thing.new | |
end | |
it "does something" do | |
@thing.should do_something | |
end | |
it "does something else" do | |
thing = Thing.new | |
thing.should do_something_else | |
end | |
end | |
# 3a4 | |
describe Thing do | |
before do | |
@thing = Thing.new | |
end | |
it "does something" do | |
@thing.should do_something | |
end | |
it "does something else" do | |
thing.should do_something_else | |
end | |
end | |
# 3a5 | |
describe Thing do | |
before do | |
@thing = Thing.new | |
end | |
it "does something" do | |
@thing.should do_something | |
end | |
it "does something else" do | |
@thing.should do_something_else | |
end | |
end | |
# and now with let - fewer steps, no adding @ signs | |
# 3b1 | |
describe Thing do | |
let(:thing) { Thing.new } | |
it "does something" do | |
thing = Thing.new | |
thing.should do_something | |
end | |
it "does something else" do | |
thing = Thing.new | |
thing.should do_something_else | |
end | |
end | |
# 3b2 | |
describe Thing do | |
let(:thing) { Thing.new } | |
it "does something" do | |
thing.should do_something | |
end | |
it "does something else" do | |
thing = Thing.new | |
thing.should do_something_else | |
end | |
end | |
# 3b2 | |
describe Thing do | |
let(:thing) { Thing.new } | |
it "does something" do | |
thing.should do_something | |
end | |
it "does something else" do | |
thing.should do_something_else | |
end | |
end |
If that makes you happy you should do that :) TBH I find myself favoring local assignment more and more.
Also using attr_reader
means you still have to declare the ivar in a before
hook (or setup
if that's how you roll). let
is therefore less code to write.
lol! Yes, it's how I roll. ;-)
let
may be fewer lines, but it also contains a conditional statement. The setup
/ attr_reader
solution has no conditionals. One other downside is that (I'm guessing) the ||=
isn't wrapped in a mutex, so there could be threading issues (were the tests to be run in multiple threads).
let is memorized per example, so I don't know where you'd see thread safety issues.
@tenderlove - you're so filled with possibilities :) Agree that this is a potential pitfall that both libs should probably warn about in docs.
TEE HEE! I love to be possible! :-D
Awww! Thanks! :-D
You're the best! :-D ❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
This also inspired me to add some docs about the oft-abused subject
: http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/Subject/ExampleMethods#subject-instance_method
I find 3a5 the most readable and consistent with the Four-Phase Test. Not sure I understand the gains of the memoization and agree with @tenderlove that the hidden conditional is a little freaky.
Why not just use attr_reader? Then skip the "add @" step (which is how I would refactor a "normal class)?