I enjoy using the let() method as it makes my specs easier to read and maintain than setting up instance variables in before(:each) blocks. The let() method can be used like this:
describe Account do
let(:account) { Factory(:account) }
subject { account }
it { should be_enabled }
context "when #disable!"do
before do
account.disable!
end
it { should be_disabled }
end
end
My main concern was that the block gets evaluated everytime the method is called. In the example above, Factory(:account) will run and create a new record for every single spec.
To increase our specs performances let’s refactor this and setup the account in a before(:all) block.
describe Account do
before(:all) do
@account= Factory(:account)
end
let(:account) { @account.reload }
#...
end
The account is now setup once before the specs get run. Each spec will be run in a separate transaction to prevent side effects. The account will be rolled back to its initial state before each spec then. Since ActiveRecord is not aware of the rollback we reload the account object from the database every time it’s called.
Specs are now faster but I want them to be as pretty as they were. Let’s make a little helper called set().
Sweeeet! You can now write the following:
describe Account do
set(:account) { Factory(:account) }
#...
end
The records created by set() will remain in your database. You can use DatabaseCleaner with the :truncation strategy to clean up your database. So far in RSpec 2.0, before(:all) runs before all describe/context/it while after(:all) runs after every single describe/context/it. Just make sure that you call DatabaseCleaner.clean in a before(:all) or after(:suite) blocks then. :)
I hope you’ll enjoy using this little helper. It’s very young and it has been tested with RSpec 2 only, so fill free to fill up the comments with enhancements and bug reports!
This blog is about Agile project management, Ruby programming and other cool things. I haven't published anything here since 2011. Find the latest and greatest on pcreux.com!
Speed up RSpec with set()
I enjoy using the
let()
method as it makes my specs easier to read and maintain than setting up instance variables inbefore(:each)
blocks. Thelet()
method can be used like this:describe Account
do
let(
:account
) { Factory(
:account
) }
subject { account }
it { should be_enabled }
context
"when #disable!"
do
before
do
account.disable!
end
it { should be_disabled }
end
end
My main concern was that the block gets evaluated everytime the method is called. In the example above,
Factory(:account)
will run and create a new record for every single spec.To increase our specs performances let’s refactor this and setup the account in a
before(:all)
block.describe Account
do
before(
:all
)
do
@account
= Factory(
:account
)
end
let(
:account
) {
@account
.reload }
#...
end
The account is now setup once before the specs get run. Each spec will be run in a separate transaction to prevent side effects. The account will be rolled back to its initial state before each spec then. Since ActiveRecord is not aware of the rollback we reload the account object from the database every time it’s called.
Specs are now faster but I want them to be as pretty as they were. Let’s make a little helper called
set()
.Sweeeet! You can now write the following:
describe Account
do
set(
:account
) { Factory(
:account
) }
#...
end
The records created by
set()
will remain in your database. You can use DatabaseCleaner with the:truncation
strategy to clean up your database. So far in RSpec 2.0,before(:all)
runs before all describe/context/it whileafter(:all)
runs after every single describe/context/it. Just make sure that you callDatabaseCleaner.clean
in abefore(:all)
orafter(:suite)
blocks then. :)I hope you’ll enjoy using this little helper. It’s very young and it has been tested with RSpec 2 only, so fill free to fill up the comments with enhancements and bug reports!
rspec-set is now available as a gem