-
-
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)?