Let vs ivar w/ before block

Am I correct in understanding that the point of using let is that it can
minimize database calls due to memoization?

describe “#something” do

let(:something) = Something.groovy_scope

it “does x” do
something.first.x.should have_coolness
end

it “does y” do
something.first.y.should_not have_coolness
end

end

vs.

describe “#something” do

before :each do
@something = Something.groovy_scope
end

it “does x” do
@something.first.x.should_not have_coolness
end

it “does y” do
@something.first.y.should_not have_coolness
end

end

Is that the proper usage?

Patrick J. Collins
http://collinatorstudios.com

Am I correct in understanding that the point of using let is that it can
minimize database calls due to memoization?

describe “#something” do

let(:something) = Something.groovy_scope

and obviously I meant let(:something) { … }, not =

(oops)…

Patrick J. Collins
http://collinatorstudios.com

On Sep 30, 2011, at 2:48 PM, Patrick J. Collins wrote:

before :each do

end

Is that the proper usage?

Proper usage, sure, but the memoization is only within each example -
not across examples. That way you can do this:

let(:thing) { Thing.new }

it “does something” do
thing.blah
thing.whatever
thing.yet_again
end

In that case each reference to thing returns the same object.

Make sense?

In that case each reference to thing returns the same object.

Make sense?

Hmm… now I am confused…

What is the difference between:

describe “Foo” do

let(:foo) { Foo.new }

it “is tubular” do
foo.bar
foo.baz
end

it “is gnarly” do
foo.gnarl
foo.wurd_up
end

end

vs.

describe “Foo” do

before :each do
@foo = Foo.new
end

it “seems just as tubular as the foo w/ let” do
@foo.bar
@foo.baz
end

it “seems just as gnarly as the foo w/ let” do
foo.gnarl
foo.wurd_up
end

end

I am not seeing any difference…?

Patrick J. Collins
http://collinatorstudios.com

On 30/09/11 3:58 PM, David C. wrote:

end
let(:foo) { Foo.new }

it “seems just as tubular as the foo w/ let” do

end
thing = Thing.new
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

One thing I noticed, and something that always catches me out is the
fact that the 'let’ted object doesn’t get instantiated until it gets
referenced. Therefore,

describe “all” do
let(:foo) { Foo.create! }

 it "returns the created object" do
     Foo.all.should include(foo)
 end

end

… fails, since at the time of calling :all, the ‘foo’ object hasn’t
been referred yet, and hence the block hasn’t executed. “Foo.all” in the
case above returns an empty array, which wouldn’t have been the case
with an instance object created in “before(:each)”.

Srushti
http://c42.in

On Sep 30, 2011, at 3:31 PM, Patrick J. Collins wrote:

In that case each reference to thing returns the same object.

end
@foo.bar
I am not seeing any difference…?
There is not, really, other than how the declaration of foo is expressed
and referenced. This evolved out of a common pattern in TDD:

1:

describe “something” do
it “does something” do
thing = Thing.new
thing.do_something.should have_some_outcome
end
end

2:

describe “something” do
it “does something” do
thing = Thing.new
thing.do_something.should have_some_outcome
end

it “does something else” do
thing = Thing.new
thing.do_something_else.should have_some_other_outcome
end
end

Now there is duplication so we can refactor out the declaration of
thing. It takes less work and is less error prone to change it to a let
declaration than to change the references to thing to an instance
variable declared in a before hook.

Cheers,
David

On Sep 30, 2011, at 4:32 PM, Srushti Ambekallu wrote:

thing.yet_again

end

end
end
it “does something else” do


   Foo.all.should include(foo)

end
end

… fails, since at the time of calling :all, the ‘foo’ object hasn’t been
referred yet, and hence the block hasn’t executed. “Foo.all” in the case above
returns an empty array, which wouldn’t have been the case with an instance object
created in “before(:each)”.

Srushti
http://c42.in

That’s one of the benefits of let :slight_smile: You can use it to declare objects
but they only get instantiated when you reference them.

See
https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/let-and-let

Proper usage, sure, but the memoization is only within each example - not
across examples. That way you can do this:

So regarding objects persisting over multiple examples-- I was told
repeatedly
by experienced RSpec peeps to not use before(:all)…

But in a case like:

before(:each) do
@user = create_user
create_user_item(:user => @user)
end

it “has an item” do
@user.user_item.should_not be_nil
end

it “rocks the house” do
@user.user_item.should respond_to(:rocks_the_house)
end

…etc…

It seems like this is an instance where before :all, really would shine
because
it would not require records to be repeatedly created…

Do you guys feel like before(:all) is just bad because of the
possibility of a
method call in one example changing the state and therefore breaking
future
examples and not having it be clear as to why… ?

Patrick J. Collins
http://collinatorstudios.com

On 30/09/11 6:24 PM, Patrick J. Collins wrote:

end

http://collinatorstudios.com


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

I don’t know if object creation (including the corresponding database
calls) are really expensive enough that I would worry about optimising
that (unless you’re getting it anyway, without losing anything in the
process, like with ‘let’). Occasionally, for some reason I’ll end up
using a ‘before(:all)’ for one isolated scenario, but inevitably a few
months down the line, I’ll end up wasting a couple of hours on a weird
failing test, until I look closely enough to notice the “:all”.

So, unless I’m doing something that’s prohibitively expensive (I haven’t
found anything that would qualify in any of my projects) I’m not likely
to create anything in a ‘before(:all)’.

Srushti
http://c42.in

On 1 Oct 2011, at 00:36, Srushti Ambekallu wrote:

On 30/09/11 6:24 PM, Patrick J. Collins wrote:

So regarding objects persisting over multiple examples-- I was told repeatedly
by experienced RSpec peeps to not use before(:all)

I don’t know if object creation (including the corresponding database calls) are
really expensive enough that I would worry about optimising that (unless you’re
getting it anyway, without losing anything in the process, like with ‘let’).
Occasionally, for some reason I’ll end up using a ‘before(:all)’ for one isolated
scenario, but inevitably a few months down the line, I’ll end up wasting a couple
of hours on a weird failing test, until I look closely enough to notice the
“:all”.

So, unless I’m doing something that’s prohibitively expensive (I haven’t found
anything that would qualify in any of my projects) I’m not likely to create
anything in a ‘before(:all)’.

I’ll second that. It’s better to feel the pain of the multiple database
hits and refactor it out in the code (can you separate more of the logic
and persistence?), than try to optimise the test run by introducing
shared state. In the long run, the former will give you many faster test
runs through better design, where as the latter will give you a few
faster tests now at the risk of - as Srushti points out - stepping on a
landmine later.

HTH

Ash


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashmoran