unit_record 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|