unit_record 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +10 -15
- data/Rakefile +7 -9
- data/lib/unit_record.rb +6 -2
- data/lib/unit_record/column_cacher.rb +54 -0
- data/lib/unit_record/column_extension.rb +7 -0
- data/lib/unit_record/disconnected_active_record.rb +3 -5
- data/test/db/schema.rb +13 -0
- data/test/functional/column_cacher_test.rb +19 -0
- data/test/functional/column_test.rb +23 -0
- data/test/{disconnecting → functional}/disconnected_active_record_test.rb +2 -2
- data/test/functional/disconnected_fixtures_test.rb +7 -0
- data/test/{disconnecting → functional}/disconnected_test_case_test.rb +2 -2
- data/test/{disconnecting/disconnecting_test_helper.rb → functional/functional_test_helper.rb} +0 -0
- data/test/test_helper.rb +3 -7
- data/test/unit/column_extension_test.rb +33 -0
- metadata +12 -10
- data/lib/unit_record/column_dumper.rb +0 -52
- data/test/caching/column_dumper_test.rb +0 -20
- data/test/db/columns.rb +0 -9
- data/test/disconnecting/disconnected_fixtures_test.rb +0 -7
- data/test/schema.rb +0 -6
data/README
CHANGED
@@ -17,11 +17,7 @@ One huge benefit to disconnecting unit tests from the database is having a faste
|
|
17
17
|
|
18
18
|
== Installation
|
19
19
|
|
20
|
-
|
21
|
-
ruby script/plugin install http://unit-test-ar.rubyforge.org/svn/trunk/unit_record/
|
22
|
-
|
23
|
-
Or with piston:
|
24
|
-
piston import http://unit-test-ar.rubyforge.org/svn/trunk/unit_record/ vendor/plugins/unit_record
|
20
|
+
gem install unit_record
|
25
21
|
|
26
22
|
== Usage
|
27
23
|
|
@@ -46,24 +42,23 @@ The <tt>functional_test_helper.rb</tt> file should require <tt>test_helper.rb</t
|
|
46
42
|
|
47
43
|
For moving unit tests, you have a few options. I recommend moving them to unit/models and then disconnecting your unit tests from the database. Any tests that fail should then be modified to not hit the database or moved to functional/models.
|
48
44
|
|
49
|
-
== Caching Columns
|
50
|
-
|
51
|
-
The plugin disconnects models from the database by caching the column metadata. This is done through a rake task:
|
52
|
-
rake db:columns:dump
|
53
|
-
|
54
|
-
The rake task creates a db/columns.rb file which will be used in the tests. If you have a custom build/test rake task, you may just want to insert this task before you run your unit tests. Otherwise, you can automatically have it run before <tt>test:units</tt> as so:
|
55
|
-
Rake::Task["test:units"].enhance ["db:columns:dump"]
|
56
|
-
|
57
45
|
== Disconnecting
|
58
46
|
|
59
47
|
In the <tt>test/unit/unit_test_helper.rb</tt> file you created when restructuring your test directory, you should add these lines:
|
60
48
|
require File.dirname(__FILE__) + "/../test_helper"
|
49
|
+
require "unit_record"
|
61
50
|
ActiveRecord::Base.disconnect!
|
62
51
|
|
63
|
-
The <tt>disconnect!</tt> method will do everything necessary
|
52
|
+
The <tt>disconnect!</tt> method will do everything necessary to run your unit tests without hitting the database. For now, it connects to the database and caches the columns in a file (db/columns.rb) before disconnecting. A later version will not need to connect at all.
|
53
|
+
|
54
|
+
== Limitations
|
55
|
+
|
56
|
+
* UnitRecord currently only works when all models use convention for table names.
|
64
57
|
|
65
58
|
== Thanks
|
66
59
|
Thanks to Jay Fields for the original implementation:
|
67
60
|
http://blog.jayfields.com/2007/03/rails-activerecord-unit-testing-part-ii.html
|
68
61
|
|
69
|
-
|
62
|
+
== License
|
63
|
+
Released under Ruby's license.
|
64
|
+
http://www.ruby-lang.org/en/LICENSE.txt
|
data/Rakefile
CHANGED
@@ -8,24 +8,22 @@ desc "Default: run tests"
|
|
8
8
|
task :default => :test
|
9
9
|
|
10
10
|
desc "Run all tests"
|
11
|
-
task :test => %w[test:
|
11
|
+
task :test => %w[test:unit test:functional]
|
12
12
|
|
13
|
-
|
14
|
-
Rake::TestTask.new("test:caching") do |t|
|
13
|
+
Rake::TestTask.new("test:unit") do |t|
|
15
14
|
t.libs << 'lib'
|
16
|
-
t.pattern = 'test/
|
15
|
+
t.pattern = 'test/unit/**/*_test.rb'
|
17
16
|
t.verbose = true
|
18
17
|
end
|
19
18
|
|
20
|
-
|
21
|
-
Rake::TestTask.new("test:disconnecting") do |t|
|
19
|
+
Rake::TestTask.new("test:functional") do |t|
|
22
20
|
t.libs << 'lib'
|
23
|
-
t.pattern = 'test/
|
21
|
+
t.pattern = 'test/functional/**/*_test.rb'
|
24
22
|
t.verbose = true
|
25
23
|
end
|
26
24
|
|
27
25
|
desc "Generate documentation"
|
28
|
-
Rake::RDocTask.new(:
|
26
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
29
27
|
rdoc.rdoc_dir = "doc"
|
30
28
|
rdoc.title = "UnitRecord"
|
31
29
|
rdoc.options << '--line-numbers'
|
@@ -42,7 +40,7 @@ Gem::manage_gems
|
|
42
40
|
specification = Gem::Specification.new do |s|
|
43
41
|
s.name = "unit_record"
|
44
42
|
s.summary = "UnitRecord enables unit testing without hitting the database."
|
45
|
-
s.version = "0.
|
43
|
+
s.version = "0.2.0"
|
46
44
|
s.author = "Dan Manges"
|
47
45
|
s.description = "UnitRecord enables unit testing without hitting the database."
|
48
46
|
s.email = "daniel.manges@gmail.com"
|
data/lib/unit_record.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
require "unit_record/
|
1
|
+
require "unit_record/column_cacher"
|
2
|
+
require "unit_record/column_extension"
|
2
3
|
require "unit_record/disconnected_active_record"
|
3
4
|
require "unit_record/disconnected_test_case"
|
4
5
|
require "unit_record/disconnected_fixtures"
|
6
|
+
|
7
|
+
require "active_record/fixtures"
|
8
|
+
|
9
|
+
ActiveRecord::ConnectionAdapters::Column.send :include, UnitRecord::ColumnExtension
|
5
10
|
ActiveRecord::Base.extend UnitRecord::DisconnectedActiveRecord
|
6
11
|
Test::Unit::TestCase.extend UnitRecord::DisconnectedTestCase
|
7
|
-
require "active_record/fixtures"
|
8
12
|
Fixtures.extend UnitRecord::DisconnectedFixtures
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module UnitRecord
|
2
|
+
class ColumnCacher
|
3
|
+
include ActiveRecord::ConnectionAdapters::SchemaStatements
|
4
|
+
|
5
|
+
def self.cache(file)
|
6
|
+
(class << ActiveRecord::Schema; self; end).class_eval do
|
7
|
+
def define(options={}, &block)
|
8
|
+
UnitRecord::ColumnCacher.new.instance_eval(&block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
load file
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_index(table_name, column_name, options = {})
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_table(table_name, options={})
|
18
|
+
table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
|
19
|
+
table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
|
20
|
+
yield table_definition
|
21
|
+
if model = model_for_table(table_name)
|
22
|
+
(class << model; self; end).class_eval do
|
23
|
+
define_method(:columns) do
|
24
|
+
table_definition.columns.map do |c|
|
25
|
+
ActiveRecord::ConnectionAdapters::Column.new(c.name.to_s, c.default, c.sql_type, c.null)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def native_database_types
|
33
|
+
# Copied from the MysqlAdapter so ColumnDefinition#sql_type will work
|
34
|
+
{
|
35
|
+
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
|
36
|
+
:string => { :name => "varchar", :limit => 255 },
|
37
|
+
:text => { :name => "text" },
|
38
|
+
:integer => { :name => "int", :limit => 11 },
|
39
|
+
:float => { :name => "float" },
|
40
|
+
:decimal => { :name => "decimal" },
|
41
|
+
:datetime => { :name => "datetime" },
|
42
|
+
:timestamp => { :name => "datetime" },
|
43
|
+
:time => { :name => "time" },
|
44
|
+
:date => { :name => "date" },
|
45
|
+
:binary => { :name => "blob" },
|
46
|
+
:boolean => { :name => "tinyint", :limit => 1 }
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def model_for_table(table)
|
51
|
+
table.to_s.classify.constantize rescue nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -5,10 +5,6 @@ module UnitRecord
|
|
5
5
|
end
|
6
6
|
def disconnect!
|
7
7
|
return if disconnected?
|
8
|
-
columns_file = File.join(RAILS_ROOT, "db", "columns.rb")
|
9
|
-
File.open(columns_file, "w") do |file|
|
10
|
-
UnitRecord::ColumnDumper.dump(ActiveRecord::Base.connection, file)
|
11
|
-
end
|
12
8
|
(class << self; self; end).class_eval do
|
13
9
|
def connection
|
14
10
|
raise "ActiveRecord is disconnected; database access is unavailable in unit tests."
|
@@ -20,9 +16,11 @@ module UnitRecord
|
|
20
16
|
true
|
21
17
|
end
|
22
18
|
end
|
23
|
-
load columns_file
|
24
19
|
Fixtures.disconnect!
|
25
20
|
Test::Unit::TestCase.disconnect!
|
21
|
+
old_columns_file = File.join(RAILS_ROOT, 'db', 'columns.rb')
|
22
|
+
File.delete old_columns_file if File.exists?(old_columns_file)
|
23
|
+
ColumnCacher.cache(RAILS_ROOT + "/db/schema.rb")
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
data/test/db/schema.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :preferences, :force => true do |t|
|
3
|
+
t.column :some_count, :integer
|
4
|
+
t.column :show_help, :boolean, :default => true
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table :people, :force => true do |t|
|
8
|
+
t.column :first_name, :string
|
9
|
+
t.column :last_name, :string
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index "people", ["first_name"]
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/functional_test_helper"
|
2
|
+
|
3
|
+
functional_tests do
|
4
|
+
test "caching columns with no defaults or not nulls" do
|
5
|
+
assert_equal [
|
6
|
+
ActiveRecord::ConnectionAdapters::Column.new("id", nil, "int(11) DEFAULT NULL auto_increment PRIMARY KEY", nil),
|
7
|
+
ActiveRecord::ConnectionAdapters::Column.new("first_name", nil, "varchar(255)", nil),
|
8
|
+
ActiveRecord::ConnectionAdapters::Column.new("last_name", nil, "varchar(255)", nil)
|
9
|
+
], Person.columns
|
10
|
+
end
|
11
|
+
|
12
|
+
test "caching column with default" do
|
13
|
+
assert_equal ActiveRecord::ConnectionAdapters::Column.new("show_help", true, "tinyint(1)", nil), Preference.columns.detect { |c| c.name == "show_help" }
|
14
|
+
end
|
15
|
+
|
16
|
+
test "add_index does not blow up" do
|
17
|
+
assert_nothing_raised { UnitRecord::ColumnCacher.new.add_index("people", "first_name") }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/functional_test_helper"
|
2
|
+
|
3
|
+
functional_tests do
|
4
|
+
test "instantiating" do
|
5
|
+
person = Person.new :first_name => "Dan", :last_name => "Manges"
|
6
|
+
assert_equal "Dan", person.first_name
|
7
|
+
assert_equal "Manges", person.last_name
|
8
|
+
end
|
9
|
+
|
10
|
+
test "using model with column with a default" do
|
11
|
+
record = Preference.new
|
12
|
+
assert_equal true, record.show_help?
|
13
|
+
end
|
14
|
+
|
15
|
+
test "typecasting happens for integer attributes" do
|
16
|
+
record = Preference.new
|
17
|
+
record.some_count = "42"
|
18
|
+
assert_equal 42, record.some_count
|
19
|
+
end
|
20
|
+
|
21
|
+
test "" do
|
22
|
+
end
|
23
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require File.dirname(__FILE__) + "/./
|
1
|
+
require File.dirname(__FILE__) + "/./functional_test_helper"
|
2
2
|
# The '.' is intentional to have a TestCase require a different relative path.
|
3
3
|
|
4
|
-
|
4
|
+
functional_tests do
|
5
5
|
test "accessing connection raises" do
|
6
6
|
assert_raises(RuntimeError) { ActiveRecord::Base.connection }
|
7
7
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require File.dirname(__FILE__) + "/
|
1
|
+
require File.dirname(__FILE__) + "/functional_test_helper"
|
2
2
|
|
3
|
-
|
3
|
+
functional_tests do
|
4
4
|
test "use_transactional_fixtures is false" do
|
5
5
|
assert_equal false, Test::Unit::TestCase.use_transactional_fixtures
|
6
6
|
end
|
data/test/{disconnecting/disconnecting_test_helper.rb → functional/functional_test_helper.rb}
RENAMED
File without changes
|
data/test/test_helper.rb
CHANGED
@@ -13,17 +13,13 @@ begin
|
|
13
13
|
rescue LoadError
|
14
14
|
raise "Need Mocha and Dust gems to Test"
|
15
15
|
end
|
16
|
-
|
17
|
-
ActiveRecord::Base.configurations['test'] = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
18
|
-
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
19
|
-
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'][ENV['DB'] || 'sqlite3'])
|
16
|
+
Test::Unit::TestCase.disallow_setup!
|
20
17
|
|
21
18
|
require "#{File.dirname(__FILE__)}/../init"
|
22
|
-
silence_stream(STDOUT) do
|
23
|
-
load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
|
24
|
-
end
|
25
19
|
|
26
20
|
Test::Unit::TestCase.use_transactional_fixtures = true
|
27
21
|
|
22
|
+
class Preference < ActiveRecord::Base
|
23
|
+
end
|
28
24
|
class Person < ActiveRecord::Base
|
29
25
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
+
|
3
|
+
unit_tests do
|
4
|
+
test "equality" do
|
5
|
+
column1 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, nil)
|
6
|
+
column2 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, nil)
|
7
|
+
assert_equal column1, column2
|
8
|
+
end
|
9
|
+
|
10
|
+
test "non-equality on name" do
|
11
|
+
column1 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, nil)
|
12
|
+
column2 = ActiveRecord::ConnectionAdapters::Column.new("different name", nil, :string, nil)
|
13
|
+
assert column1 != column2
|
14
|
+
end
|
15
|
+
|
16
|
+
test "non-equality on sql_type" do
|
17
|
+
column1 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, nil)
|
18
|
+
column2 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :text, nil)
|
19
|
+
assert column1 != column2
|
20
|
+
end
|
21
|
+
|
22
|
+
test "non-equality on default" do
|
23
|
+
column1 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, nil)
|
24
|
+
column2 = ActiveRecord::ConnectionAdapters::Column.new("name", "Dan", :string, nil)
|
25
|
+
assert column1 != column2
|
26
|
+
end
|
27
|
+
|
28
|
+
test "non-equality on null" do
|
29
|
+
column1 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, nil)
|
30
|
+
column2 = ActiveRecord::ConnectionAdapters::Column.new("name", nil, :string, true)
|
31
|
+
assert column1 != column2
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.3
|
|
3
3
|
specification_version: 1
|
4
4
|
name: unit_record
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-08-
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-08-16 00:00:00 -04:00
|
8
8
|
summary: UnitRecord enables unit testing without hitting the database.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -30,18 +30,20 @@ authors:
|
|
30
30
|
- Dan Manges
|
31
31
|
files:
|
32
32
|
- lib/unit_record.rb
|
33
|
-
- lib/unit_record/
|
33
|
+
- lib/unit_record/column_cacher.rb
|
34
|
+
- lib/unit_record/column_extension.rb
|
34
35
|
- lib/unit_record/disconnected_active_record.rb
|
35
36
|
- lib/unit_record/disconnected_fixtures.rb
|
36
37
|
- lib/unit_record/disconnected_test_case.rb
|
37
|
-
- test/schema.rb
|
38
38
|
- test/test_helper.rb
|
39
|
-
- test/
|
40
|
-
- test/
|
41
|
-
- test/
|
42
|
-
- test/
|
43
|
-
- test/
|
44
|
-
- test/
|
39
|
+
- test/db/schema.rb
|
40
|
+
- test/functional/column_cacher_test.rb
|
41
|
+
- test/functional/column_test.rb
|
42
|
+
- test/functional/disconnected_active_record_test.rb
|
43
|
+
- test/functional/disconnected_fixtures_test.rb
|
44
|
+
- test/functional/disconnected_test_case_test.rb
|
45
|
+
- test/functional/functional_test_helper.rb
|
46
|
+
- test/unit/column_extension_test.rb
|
45
47
|
- Rakefile
|
46
48
|
- init.rb
|
47
49
|
- README
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'erb'
|
2
|
-
module UnitRecord
|
3
|
-
class ColumnDumper
|
4
|
-
private_class_method :new
|
5
|
-
|
6
|
-
def self.dump(connection, stream)
|
7
|
-
new(connection).write_to(stream)
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize(connection)
|
11
|
-
@connection = connection
|
12
|
-
end
|
13
|
-
|
14
|
-
def columns_by_model
|
15
|
-
@columns_by_model ||= tables.inject({}) do |hash,table|
|
16
|
-
model = model_for_table(table)
|
17
|
-
hash[model.to_s] = columns(table) if model
|
18
|
-
hash
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def columns(table)
|
23
|
-
@connection.columns(table)
|
24
|
-
end
|
25
|
-
|
26
|
-
def model_for_table(table)
|
27
|
-
table.classify.constantize rescue nil
|
28
|
-
end
|
29
|
-
|
30
|
-
def tables
|
31
|
-
@connection.tables
|
32
|
-
end
|
33
|
-
|
34
|
-
def write_to(stream)
|
35
|
-
template = ERB.new <<-END, nil, '-'
|
36
|
-
<% columns_by_model.keys.sort.each do |model| -%>
|
37
|
-
<%= model %>.class_eval do
|
38
|
-
def self.columns
|
39
|
-
[
|
40
|
-
<%- columns_by_model[model].each do |column| -%>
|
41
|
-
ActiveRecord::ConnectionAdapters::Column.new(<%= column.name.to_s.inspect %>, <%= column.default.inspect %>, <%= column.sql_type.inspect %>, <%= column.null.inspect%>),
|
42
|
-
<%- end -%>
|
43
|
-
]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
<%- end -%>
|
47
|
-
END
|
48
|
-
text = template.result binding
|
49
|
-
stream.write text
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
-
|
3
|
-
class ColumnDumperTest < Test::Unit::TestCase
|
4
|
-
test "dumping columns" do
|
5
|
-
stream = StringIO.new
|
6
|
-
UnitRecord::ColumnDumper.dump(ActiveRecord::Base.connection, stream)
|
7
|
-
expected = <<-END
|
8
|
-
Person.class_eval do
|
9
|
-
def self.columns
|
10
|
-
[
|
11
|
-
ActiveRecord::ConnectionAdapters::Column.new("id", nil, "INTEGER", false),
|
12
|
-
ActiveRecord::ConnectionAdapters::Column.new("first_name", nil, "varchar(255)", true),
|
13
|
-
ActiveRecord::ConnectionAdapters::Column.new("last_name", nil, "varchar(255)", true),
|
14
|
-
]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
END
|
18
|
-
assert_equal expected, stream.string
|
19
|
-
end
|
20
|
-
end
|
data/test/db/columns.rb
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
Person.class_eval do
|
2
|
-
def self.columns
|
3
|
-
[
|
4
|
-
ActiveRecord::ConnectionAdapters::Column.new("id", nil, "INTEGER", false),
|
5
|
-
ActiveRecord::ConnectionAdapters::Column.new("first_name", nil, "varchar(255)", true),
|
6
|
-
ActiveRecord::ConnectionAdapters::Column.new("last_name", nil, "varchar(255)", true),
|
7
|
-
]
|
8
|
-
end
|
9
|
-
end
|