modelizer 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,8 @@
1
+ === 5.0.0 / 2011-09-11
2
+
3
+ * Complete breaking change, now provides unified fixtures/factories.
4
+ * Require Ruby 1.9.2 or better.
5
+
1
6
  === 4.0.0 / 2011-06-14
2
7
 
3
8
  * Update for AR 3.1.
@@ -4,7 +4,7 @@ Manifest.txt
4
4
  README.rdoc
5
5
  Rakefile
6
6
  lib/modelizer.rb
7
+ lib/modelizer/all.rb
7
8
  lib/modelizer/assertions.rb
8
9
  lib/modelizer/validations.rb
9
10
  test/test_assertions.rb
10
- test/test_modelizer.rb
@@ -5,72 +5,84 @@
5
5
  == Description
6
6
 
7
7
  Need a simple, consistent way to create model instances and check
8
- validations in your ActiveRecord 3.1+ tests? Use the Modelizer.
8
+ validations in your ActiveRecord 3.1+ tests? Use the Modelizer. Just
9
+ don't trust the docs, since lots changed in 5.x and I got lazy.
9
10
 
10
11
  == Examples
11
12
 
12
- First, enable the Modelizer. I do it in <tt>test/test_helper.rb</tt>:
13
+ First, enable the Modelizer in your test helper. In Rails, try
14
+ something like:
15
+
16
+ require "modelizer/all"
13
17
 
14
18
  class ActiveSupport::TestCase
15
19
  include Modelizer
20
+ extend Modelizer::Validations
16
21
  end
17
22
 
18
- Next, define a model template. I generally do this in the unit test
19
- for the model until I need to use the template somewhere else. As soon
20
- as it's used in multiple places, I move it to a reopened
21
- <tt>ActiveSupport::TestCase</tt> in <tt>test/test_helper.rb</tt>.
23
+ Next, define some fixtures and factories. Modelizer will load these
24
+ when the module is included, using
25
+ <tt>"test/{factories,fixtures}/**/*.rb"</tt> as a default glob. Change
26
+ it by setting <tt>Modelizer.glob</tt> before module inclusion.
27
+
28
+ Fixture and factory definitions look remarkably similar. The only real
29
+ difference is that fixtures get loaded into the DB once at module
30
+ inclusion and factories don't. Factories will also generally use
31
+ autogenerated/random data generators. Some examples:
32
+
33
+ # from test/fixtures/user.rb
22
34
 
23
- class UserTest < ActiveSupport::TestCase
35
+ fixture :user, User do |u|
36
+ u.account = use :account
37
+ u.email = "default@example.org
38
+ u.name = "A User"
39
+ u.password = "123456"
40
+ u.state = "active"
41
+ end
24
42
 
25
- # a simple list of attributes
26
- model_template_for User, :name => "Bob"
27
43
 
28
- # or a block for lazy evaluation
29
- model_template_for User do
30
- { :name => "Bob", :address => addresses(:default) }
31
- end
44
+ # from test/factories/user.rb
32
45
 
46
+ factory :user, User do |u|
47
+ u.account = use :account
48
+ u.email = Faker::Internet.email
49
+ u.name = Faker::Name.name
50
+ u.password = Faker::Lorem.words(1).first
33
51
  end
34
52
 
35
- This declaration generates a bunch of instance methods for you:
53
+ To get a reference to a fixture, the <tt>use</tt> method is added to your
54
+ test class:
55
+
56
+ def test_something
57
+ refute_equal use(:artist).name, use("artist/child").name
58
+ end
36
59
 
37
- * <tt>def valid_user_attributes(extras = {})</tt>
38
- * <tt>def valid_user_attributes_without(*excluded)</tt>
39
- * <tt>def new_user(extras = {})</tt>
40
- * <tt>def new_user_without(*excluded)</tt>
41
- * <tt>def create_user(extras = {})</tt>
42
- * <tt>def create_user!(extras = {})</tt>
43
- * <tt>def create_user_without(*excluded)</tt>
44
- * <tt>def create_user_without!(*excluded)</tt>
60
+ To get an instance from a factory, the <tt>build</tt> and <tt>create</tt> methods
61
+ are available:
45
62
 
46
- It also generates a test to make sure your model template is valid.
63
+ def test_something_else
64
+ assert_equal "foo", build(:artist, name: "foo").name
65
+ refute create(:artist).new_record?
66
+ end
47
67
 
48
68
  === Custom Assertions
49
69
 
50
- Modelizer adds one additional assertion, <tt>assert_invalid</tt>.
70
+ If you require <tt>"modelizer/all"</tt> or include
71
+ <tt>Modelizer::Assertions</tt>, Modelizer adds one additional
72
+ assertion, <tt>assert_invalid</tt>.
51
73
 
52
74
  assert_invalid :email, model, /is bad/
53
75
 
54
76
  The third argument is optional.
55
77
 
56
- === Using in Tests
57
-
58
- class UserTest < ActiveSupport::TestCase
59
- model_template_for User, :name => "Bob"
60
-
61
- def test_pointless_stuff
62
- assert new_user.valid?
63
- assert_invalid :name, new_user_without(:name)
64
-
65
- assert !create_user.new_record?
78
+ def test_pointless_stuff
79
+ assert new_user.valid?
80
+ assert_invalid :name, build(:artist, name: nil)
81
+ end
66
82
 
67
- assert_raise do
68
- create_user_without! :name
69
- end
83
+ === Testing Validations
70
84
 
71
- assert_equal "Fred", new_user(:name => "Fred").name
72
- end
73
- end
85
+ I should really write some docs for this.
74
86
 
75
87
  == Installation
76
88
 
data/Rakefile CHANGED
@@ -10,4 +10,6 @@ Hoe.spec "modelizer" do
10
10
  self.history_file = "CHANGELOG.rdoc"
11
11
  self.readme_file = "README.rdoc"
12
12
  self.testlib = :minitest
13
+
14
+ require_ruby_version ">= 1.9.2"
13
15
  end
@@ -1,138 +1,102 @@
1
- require "modelizer/assertions"
2
- require "modelizer/validations"
1
+ require "zlib"
3
2
 
4
3
  module Modelizer
5
4
 
6
- # Duh.
7
- VERSION = "4.0.0"
5
+ VERSION = "5.0.0"
8
6
 
9
- include Modelizer::Assertions
7
+ def build name, overrides = nil, &block
8
+ model, *initializers = Modelizer.factories[name]
9
+ raise "Can't find the \"#{name}\" factory." unless model
10
10
 
11
- # Test classes that should be considered abstract when rendering
12
- # tests for a model template.
11
+ obj = model.new
13
12
 
14
- TEST_CLASSES = []
13
+ initializers << block if block_given?
14
+ initializers.each { |i| instance_exec obj, &i }
15
15
 
16
- %w(Test::Unit::TestCase Minitest::Unit::TestCase
17
- ActiveSupport::TestCase).each do |k|
16
+ overrides.each { |k, v| obj.send "#{k}=", v } if overrides
17
+
18
+ obj
19
+ end
20
+
21
+ def create name, overrides = nil, &block
22
+ obj = build name, overrides, &block
23
+
24
+ obj.save!
18
25
 
19
- TEST_CLASSES <<
20
- k.split("::").inject(Object) { |a, b| a.const_get b } rescue nil
26
+ obj
21
27
  end
22
28
 
23
- @@cache = {}
24
- def self.cache; @@cache end
29
+ def use name
30
+ model, id = Modelizer.ids[name]
31
+ raise "Can't find the \"#{name}\" fixture." unless model
25
32
 
26
- def self.included target
27
- target.extend ClassMethods
28
- target.extend Modelizer::Validations
33
+ model.find id
29
34
  end
30
35
 
31
- def self.method_name_for model_class
32
- underscore model_class.name
36
+ class Context < Struct.new(:instances)
37
+ def identify name
38
+ Modelizer.identify name
39
+ end
40
+
41
+ def use name
42
+ instances[name] or raise "Can't find the \"#{name}\" fixture."
43
+ end
33
44
  end
34
45
 
35
- def self.model_class_for test_class
36
- test_class.name.gsub(/Test$/, "").constantize
46
+ def self.included klass
47
+ Dir[glob].sort.each { |f| instance_eval File.read(f), f, 1 }
48
+
49
+ instances = {}
50
+ context = Context.new instances
51
+
52
+ fixtures.each do |name, value|
53
+ instances[name] = value.first.new
54
+ end
55
+
56
+ instances.each do |name, obj|
57
+ _, *initializers = fixtures[name]
58
+ initializers.each { |i| context.instance_exec obj, &i }
59
+
60
+ obj.id = identify name
61
+ ids[name] = [obj.class, obj.id]
62
+ end
63
+
64
+ ActiveRecord::Base.transaction do
65
+ instances.each { |_, obj| obj.save! }
66
+ end
37
67
  end
38
68
 
39
- def self.underscore classname
40
- classname.gsub(/::/, '_').
41
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
42
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
43
- tr("-", "_").
44
- downcase
69
+ class << self
70
+ attr_accessor :glob
45
71
  end
46
72
 
47
- def assign_model_template_attributes model, attributes
48
- model.assign_attributes attributes, without_protection: true
49
- model
73
+ self.glob = "test/{factories,fixtures}/**/*.rb"
74
+
75
+ def self.cache
76
+ @cache ||= {}
50
77
  end
51
78
 
52
- def valid_model_template_attributes klass, extras = {}
53
- defaults, block = ::Modelizer.cache[klass]
54
- lazy = block && instance_eval(&block)
55
- [defaults, lazy, extras].compact.inject { |t, s| t.merge s }
79
+ def self.factory name, model, &initializer
80
+ factories[name] = [model, initializer]
56
81
  end
57
82
 
58
- def valid_model_template_attributes_without klass, excluded
59
- valid_model_template_attributes(klass).delete_if do |k, v|
60
- excluded.include? k
61
- end
83
+ def self.factories
84
+ @factories ||= {}
62
85
  end
63
86
 
64
- module ClassMethods
65
- def model_template_for klass, defaults = {}, &block
66
- if defaults.nil? && !block
67
- raise ArgumentError, "default attributes or lazy block required"
68
- end
69
-
70
- ::Modelizer.cache[klass] = [defaults, block]
71
-
72
- model = ::Modelizer.method_name_for klass
73
- klass = klass.name
74
-
75
- module_eval <<-END, __FILE__, __LINE__ + 1
76
- def valid_#{model}_attributes extras = {}
77
- valid_model_template_attributes #{klass}, extras
78
- end
79
-
80
- def valid_#{model}_attributes_without *excluded
81
- valid_model_template_attributes_without #{klass}, excluded
82
- end
83
-
84
- def new_#{model} extras = {}
85
- assign_model_template_attributes #{klass}.new,
86
- valid_model_template_attributes(#{klass}, extras)
87
- end
88
-
89
- def new_#{model}_without *excluded
90
- assign_model_template_attributes #{klass}.new,
91
- valid_model_template_attributes_without(#{klass}, excluded)
92
- end
93
-
94
- def create_#{model} extras = {}
95
- (m = new_#{model}(extras)).save; m
96
- end
97
-
98
- def create_#{model}! extras = {}
99
- (m = new_#{model}(extras)).save!; m
100
- end
101
-
102
- def create_#{model}_without *excluded
103
- (m = new_#{model}_without(*excluded)).save; m
104
- end
105
-
106
- def create_#{model}_without! *excluded
107
- (m = new_#{model}_without(*excluded)).save!; m
108
- end
109
- END
110
-
111
- # Install a test that ensures the model template is valid. If
112
- # the template is defined in one of the abstract test
113
- # superclasses, generate a whole new testcase. If it's in a
114
- # concrete test, just generate a method.
115
-
116
- file, line = caller.first.split ":"
117
- line = line.to_i
118
-
119
- test = <<-END
120
- def test_model_template_for_#{model}
121
- assert (m = new_#{model}).valid?,
122
- "#{klass} template is invalid: " +
123
- m.errors.full_messages.to_sentence
124
- end
125
- END
126
-
127
- if TEST_CLASSES.include? self
128
- eval <<-END, nil, file, line - 2
129
- class ::ModelTemplateFor#{klass}Test < ActiveSupport::TestCase
130
- #{test}
131
- end
132
- END
133
- else
134
- module_eval test, file, line - 1
135
- end
136
- end
87
+ def self.fixture name, model, &initializer
88
+ fixtures[name] = [model, initializer]
89
+ end
90
+
91
+ def self.fixtures
92
+ @fixtures ||= {}
93
+ end
94
+
95
+ def self.identify name
96
+ Zlib.crc32(name.to_s) % (2 ** 30 - 1)
97
+ end
98
+
99
+ def self.ids
100
+ @ids ||= {}
137
101
  end
138
102
  end
@@ -0,0 +1,3 @@
1
+ require "modelizer"
2
+ require "modelizer/assertions"
3
+ require "modelizer/validations"
@@ -13,4 +13,6 @@ module Modelizer
13
13
  assert_match match, model.errors.on(attribute) if match
14
14
  end
15
15
  end
16
+
17
+ include Assertions
16
18
  end
@@ -1,36 +1,23 @@
1
1
  module Modelizer
2
2
  module Validations
3
- def test_validations_for attribute, *validations
4
- @klass ||= ::Modelizer.model_class_for self
5
- @model ||= ::Modelizer.method_name_for @klass
6
-
7
- unless instance_methods.collect { |m| m.to_s }.include? "new_#{@model}"
8
- raise "no model template for #{@klass.name}"
9
- end
10
-
11
- # FIX: location in original test file
12
-
13
- validations.each do |v|
14
- test = send "validation_lambda_for_#{v}", @klass, @model, attribute
15
- define_method "test_#{attribute}_#{v}", &test
3
+ def test_presence_for plan, attribute
4
+ define_method "test_#{attribute}_presence" do
5
+ bad = build plan, attribute => nil
6
+ assert_invalid attribute, bad
16
7
  end
17
8
  end
18
9
 
19
- private
20
-
21
- def validation_lambda_for_presence klass, model, attribute
22
- lambda do
23
- assert_invalid attribute, send("new_#{model}", attribute => nil)
10
+ def test_uniqueness_for plan, attribute
11
+ define_method "test_#{attribute}_uniqueness" do
12
+ good = create plan
13
+ bad = build(plan) { |o| o.send("#{attribute}=", good.send(attribute)) }
14
+ assert_invalid attribute, bad
24
15
  end
25
16
  end
26
17
 
27
- def validation_lambda_for_uniqueness klass, model, attribute
28
- lambda do
29
- existing = klass.first
30
- assert existing, "There's at least one #{model} fixture."
31
-
32
- assert_invalid attribute,
33
- send("new_#{model}", attribute => existing.send(attribute))
18
+ def test_validations_for plan, attribute, *validations
19
+ validations.each do |validation|
20
+ send "test_#{validation}_for", plan, attribute
34
21
  end
35
22
  end
36
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modelizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 5.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,23 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-06-14 00:00:00.000000000 -05:00
13
- default_executable:
12
+ date: 2011-09-11 00:00:00.000000000Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: hoe
17
- requirement: &2151797440 !ruby/object:Gem::Requirement
16
+ requirement: &70235549949760 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
- - - ! '>='
19
+ - - ~>
21
20
  - !ruby/object:Gem::Version
22
- version: 2.9.4
21
+ version: '2.12'
23
22
  type: :development
24
23
  prerelease: false
25
- version_requirements: *2151797440
24
+ version_requirements: *70235549949760
26
25
  description: ! 'Need a simple, consistent way to create model instances and check
27
26
 
28
- validations in your ActiveRecord 3.1+ tests? Use the Modelizer.'
27
+ validations in your ActiveRecord 3.1+ tests? Use the Modelizer. Just
28
+
29
+ don''t trust the docs, since lots changed in 5.x and I got lazy.'
29
30
  email:
30
31
  - code@jbarnette.com
31
32
  executables: []
@@ -41,12 +42,11 @@ files:
41
42
  - README.rdoc
42
43
  - Rakefile
43
44
  - lib/modelizer.rb
45
+ - lib/modelizer/all.rb
44
46
  - lib/modelizer/assertions.rb
45
47
  - lib/modelizer/validations.rb
46
48
  - test/test_assertions.rb
47
- - test/test_modelizer.rb
48
49
  - .gemtest
49
- has_rdoc: true
50
50
  homepage: http://github.com/jbarnette/modelizer
51
51
  licenses: []
52
52
  post_install_message:
@@ -60,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - ! '>='
62
62
  - !ruby/object:Gem::Version
63
- version: '0'
63
+ version: 1.9.2
64
64
  required_rubygems_version: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
@@ -69,11 +69,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
69
  version: '0'
70
70
  requirements: []
71
71
  rubyforge_project: modelizer
72
- rubygems_version: 1.6.2
72
+ rubygems_version: 1.8.7
73
73
  signing_key:
74
74
  specification_version: 3
75
75
  summary: Need a simple, consistent way to create model instances and check validations
76
- in your ActiveRecord 3.1+ tests? Use the Modelizer.
76
+ in your ActiveRecord 3.1+ tests? Use the Modelizer
77
77
  test_files:
78
78
  - test/test_assertions.rb
79
- - test/test_modelizer.rb
@@ -1,14 +0,0 @@
1
- require "minitest/autorun"
2
- require "modelizer"
3
-
4
- class TestModelizer < MiniTest::Unit::TestCase
5
- def setup
6
- @klass = Class.new
7
- @klass.send :include, Modelizer
8
- end
9
-
10
- def test_adds_model_template_for_class_method
11
- assert_includes @klass.singleton_methods.collect { |m| m.to_s },
12
- "model_template_for"
13
- end
14
- end