avdi / nulldb

An ActiveRecord null database adapter for greater speed and isolation in unit tests.

This URL has Read+Write access

Avdi Grimm (author)
Sun May 31 16:25:12 -0700 2009
commit  256369b4525a7aa0f2b95c0bd53fa31f2916e65c
tree    7fd5b1f2fb78f05eb5677b7e6b35f0c26f709eea
parent  6931b2fd492fd9e30eb468533f5064ae56f6e6e3
nulldb / README
100644 144 lines (105 sloc) 4.774 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
= The NullDB Connection Adapter Plugin
 
== What
 
NullDB is the Null Object pattern as applied to ActiveRecord database
adapters. It is a database backend that translates database
interactions into no-ops. Using NullDB enables you to test your model
business logic - including +after_save+ hooks - without ever touching
a real database.
 
== How
 
Once installed, NullDB can be used much like any other ActiveRecord
database adapter:
 
  ActiveRecord::Base.establish_connection :adapter => :nulldb
 
NullDB needs to know where you keep your schema file in order to
reflect table metadata. By default it looks in
RAILS_ROOT/db/schema.rb. You can override that by setting the
+schema+ option:
 
  ActiveRecord::Base.establish_connection :adapter => :nulldb,
                                          :schema => foo/myschema.rb
 
NullDB comes with RSpec integration. To replace the database with
NullDB in all of your specs, put the following in your
spec/spec_helper:
 
  require 'nulldb_rspec'
  include NullDB::RSpec::NullifiedDatabase
 
Or if you just want to use NullDB in a specific spec context, you can
include the same module inside a context:
 
  require 'nulldb_rspec'
 
  describe Employee, "with access to the database" do
    fixtures :employees
    # ...
  end
 
  describe Employee, "with NullDB" do
    include NullDB::RSpec::NullifiedDatabase
    # ...
  end
 
NullDB::Rspec provides some custom matcher support for verifying
expectations about interactions with the database:
 
  describe Employee do
    include NullDB::RSpec::NullifiedDatabase
 
    it "should cause an insert statement to be executed" do
      Employee.create!
      Employee.connection.should have_executed(:insert)
    end
  end
 
UnitRecord-style verification that no database calls have been made at
all can be achieved by using the special +:anything+ symbol:
 
  describe "stuff that shouldn't touch the database" do
    after :each do
      Employee.connection.should_not have_executed(:anything)
    end
    # ...
  end
 
You can also experiment with putting NullDB in your database.yml:
 
  unit_test:
    adapter: nulldb
 
However, due to the way Rails hard-codes specific database adapters
into its standard Rake tasks, you may find that this generates
unexpected and difficult-to-debug behavior. Workarounds for this are
under development.
 
== Why
 
There are a number of advantages to writing unit tests that never
touch the database. The biggest is probably speed of execution - unit
tests must be fast for test-driven development to be practical.
Another is separation of concerns: unit tests should be exercising
only the business logic contained in your models, not ActiveRecord.
For more on why testing-sans-database is a god idea, see:
http://www.dcmanges.com/blog/rails-unit-record-test-without-the-database.
 
NullDB is one way to separate your unit tests from the database. It
was inspired by the ARBS[http://arbs.rubyforge.org/] and
UnitRecord[http://unit-test-ar.rubyforge.org/] libraries. It differs
from them in a couple of ways:
 
1. It works. At the time of writing both ARBS and UnitRecord were
   not working for me out of the box with Rails 2.0.
 
2. It avoids monkey-patching as much as possible. Rather than
   re-wiring the secret inner workings of ActiveRecord (and thus being
   tightly coupled to those inner workings), NullDB implements the
   same [semi-]well-documented public interface that the other standard
   database adapters, like MySQL and SQLServer, implement.
 
3. UnitRecord takes the approach of eliminating database interaction
   in tests by turning almost every database interaction into an
   exception. NullDB recognizes that ActiveRecord objects typically
   can't take two steps without consulting the database, so instead it
   turns database interactions into no-ops.
 
One concrete advantage of this null-object pattern design is that it
is possible with NullDB to test +after_save+ hooks. With NullDB, you
can call +#save+ and all of the usual callbacks will be called - but
nothing will be saved.
 
== Limitations
 
* It is *not* an in-memory database. Finds will not work. Neither
  will +reload+, currently. Test fixtures won't work either, for
  obvious reasons.
* It has only the most rudimentery schema/migration support. Complex
  migrations will probably break it.
* Lots of other things probably don't work. Patches welcome!
 
== Who
 
NullDB was written by Avdi Grimm <mailto:avdi@avdi.org>
 
== Where
 
* Homepage: http://nulldb.rubyforge.org
* Project Info: http://rubyforge.org/projects/nulldb/
* SCM: http://rubyforge.org/scm/?group_id=7512
 
== Changes
 
 * Version 0.0.1 (2007-02-18)
   - Initial Release
 * Version 0.0.2 (2007-05-31)
   - Moved to Rubyforge
 
== License
 
See the LICENSE file for licensing information.