Short presentation about how I use NullDB in my ActiveRecord projects. I generally use this approach on projects that I know will be large and will merit the tradeoffs that come with disconnecting the database. I will typically use Cucumber when taking this approach as well.
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Disconnecting the Database with ActiveRecord
1. Disconnecting the
Database with
ActiveRecord
URUG
1-27-09
Saturday, February 21, 2009
2. Disconnecting the DB
Comes with trade-offs and risks.
How big is your suite or how big do you
expect it to be?
Do you have acceptance or functional
tests that test the whole stack?
What is the skill level of your team and
experience with AR and testing?
How comfortable is your team with
stubbing?
Saturday, February 21, 2009
3. The Benefits
“A unit test that takes longer than 0.10s is a slow unit test.” - Michael Feathers in
Working Effectively with Legacy Code
Project A
2530 examples. Runs in 5:14 minutes.
Average example time: 0.1241s
Project B (in development) with NullDB
692 examples. Runs in 23.38 seconds.
Average example time: 0.0338s
Saturday, February 21, 2009
4. File Organization
Generally run suites separate.
Additional conceptual overhead of
different test files for the same
object.
Get the option to delay running
slower (functional) tests until CI.
Thats just one way... not the way I do it...
Saturday, February 21, 2009
5. NullDB
The way I use it... I mix both types of tests in
one file. NullDB is On by default:
require 'nulldb_rspec'
ActiveRecord::Base.establish_connection(:adapter => :nulldb)
unless Object.const_defined?(:Functional)
share_as :Functional do
before :all do
ActiveRecord::Base.establish_connection(:test)
end
after :all do
ActiveRecord::Base.establish_connection(:adapter => :nulldb)
end
end
end
Saturday, February 21, 2009
6. NullDB
describe PetStore, quot;#special_dogsquot; do
it quot;should return a list of all the special dogsquot; do
# given
dogs = [Dog.create!(:name => 'Fido'),
Dog.create!(:name => 'Spot'),
Dog.create!(:name => 'Cliford')]
# nulldb will populate ids
#Since Dog.find_by_complex_sql is tested we can stub with comfort
Dog.stub!(:find_by_complex_sql).and_return(dogs)
# when & then
@pet_store.special_dogs.should == quot;Fido, Spot, and Cliffordquot;
end
end
I work outside-in stubbing any methods with
SELECTs first, and then test/implement those
methods against the database.
Saturday, February 21, 2009
7. NullDB
Turn actual database on in example
groups that need a real DB:
describe Dog, quot;.find_by_complex_sqlquot; do
include Functional
it quot;should return ....quot; do
...
end
it quot;should ...quot; do
...
end
end
Saturday, February 21, 2009
8. NullDB
Gotchas and associations caveats...
class Dog < AR::Base
belongs_to :person
end
class Person < AR::Base
has_many :dogs
end
describe Person, quot;#some_method_that_uses_dogsquot; do
it quot;should ...quot; do
person = create_person
dog = create_dog(:person => person) # notice how we associate the person
person.dogs.inpsect # odd nulldb bug... need to do a patch..
person.dogs << dog # now we associate the other way
person.some_method_that_uses_dogs.should ...
end
end
Saturday, February 21, 2009
9. New version of RSpec
will having tagging...
describe Dog, quot;.find_by_complex_sqlquot;, :functional => true do
it quot;should return ....quot; do
...
end
it quot;should ...quot; do
...
end
end
You’ll be able to run just the examples you want to!
http://rspec.lighthouseapp.com/projects/5645/tickets/682-conditional-exclusion-of-example-groups
Saturday, February 21, 2009