modelfactory 0.8.1 → 0.8.9

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.
@@ -1,15 +1,15 @@
1
- == 0.8.1 2009-05-08
1
+ == 0.8.9 2009-05-19
2
+ * Renamed the required lib to 'modelfactory'
3
+ * Completely redesigned API, see the documentation in README.txt
2
4
 
5
+ == 0.8.1 2009-05-08
3
6
  * Ruby 1.9.1 compatibility
4
7
 
5
8
  == 0.8.0 2008-12-10
6
-
7
9
  * added the ability to specify multiple named types of defaults
8
10
 
9
11
  == 0.7.0 2008-11-11
10
-
11
12
  * Documentation and rubygem
12
13
 
13
14
  == 0.0.1 2008-01-25
14
-
15
15
  * Initial release
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008 Zack Hobson and Justin Balthrop, Geni.com
1
+ Copyright (c) 2008, 2009 Zack Hobson and Justin Balthrop
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -5,11 +5,18 @@ README.txt
5
5
  Rakefile
6
6
  lib/fixture_converter.rb
7
7
  lib/model_factory.rb
8
- lib/model_factory/version.rb
8
+ lib/modelfactory.rb
9
+ lib/modelfactory/factory.rb
10
+ lib/modelfactory/legacy.rb
11
+ lib/modelfactory/version.rb
9
12
  script/destroy
10
13
  script/fixtures2factories
11
14
  script/generate
12
15
  script/txt2html
13
16
  setup.rb
17
+ test/fixtures/schema.rb
18
+ test/fixtures/strict_widget.rb
19
+ test/fixtures/widget.rb
20
+ test/model_factory_legacy_test.rb
14
21
  test/model_factory_test.rb
15
22
  test/test_helper.rb
data/README.txt CHANGED
@@ -6,117 +6,76 @@ Rails applications.
6
6
  The best explanation for the motivation behind ModelFactory (and the inspiration
7
7
  for this module) comes from Dan Manges' blog: http://www.dcmanges.com/blog/38
8
8
 
9
- The idea is that instead of keeping your test data in a nearly opaque fixture
10
- file, you generate data in the test itself using a custom factory API designed
11
- for your test environment.
9
+ NOTE that the API has changed recently, but ModelFactory is still fully
10
+ backward-compatible with previous releases. For a description of the original
11
+ API see ModelFactory::Legacy.
12
12
 
13
- By creating a new module just for your test factory API you make it easier
14
- to spot factory calls in your tests and keep your factory code out of your
15
- test code. ModelFactory adds some useful facilities for generating optional
16
- defaults for commonly instantiated types. It also fakes up id generation in
17
- the ActiveRecord models created with new, to assist in unit testing without
18
- the database.
13
+ == Usage
19
14
 
20
- === A Note About Defaults
21
-
22
- The purpose of default values is to generate valid instances, not to serve as
23
- replacements for fixture data. When writing tests that use factory-generated
24
- objects, it's important never to depend on default values in your test assertions.
25
- If you depend on defaults in your tests they become more fragile and the intention
26
- is harder to discern. Alway override values you care about when using factory objects.
15
+ The essential purpose of ModelFactory is the automatic generation of valid,
16
+ opaque ActiveRecord objects whose contents are unimportant.
27
17
 
28
- If you find yourself repeating the same initialization to avoid using defaults,
29
- consider whether it would be appropriate to add a custom toplevel method to
30
- your factory module that includes this initialization. You can also specify
31
- multiple named types of defaults, described below. Be aware that both of these
32
- techniques should be used sparingly, as they can have some of the same issues
33
- as fixtures.
18
+ require 'modelfactory'
34
19
 
35
- === A Note About ID Generation
36
-
37
- Since basic ID generation is done when you instantiate objects using
38
- Factory.new_<type> it is recommended not to mix such objects with those
39
- created using Factory.create_<type>. Use the former in unit tests and
40
- use the latter in functional tests.
41
-
42
- == Using ModelFactory
43
-
44
- Put something like this in your test helper:
20
+ ModelFactory.configuration do
21
+ default(User) do |m|
22
+ m.name = "Factory User"
23
+ m.email = "user@factory.ws"
24
+ end
25
+ end
45
26
 
46
- require 'model_factory'
27
+ ModelFactory[User].create.name # => 'Factory User'
47
28
 
48
- module Factory
49
- extend ModelFactory
29
+ If you don't care for the factory creation syntax, ModelFactory defines the
30
+ factory class method on ActiveRecord models. The following is equivalent
31
+ to ModelFactory[User].create:
50
32
 
51
- # a default block accepts a class and a hash of default values
52
- default Color, {
53
- :name => 'chartreuse'
54
- }
33
+ User.factory.create
55
34
 
56
- default User, {
57
- :first_name => 'Harry',
58
- :last_name => 'Manchester',
59
- :favorite_color => default_color
60
- }
35
+ Since factory-created instances are meant to be valid, you will probably
36
+ need a way to generate unique values. ModelFactory keeps a counter for each
37
+ type that increments when each new instance is created. This counter is passed
38
+ to configuration blocks to make it easier to generate unique values:
61
39
 
62
- # Add class methods to create whatever kind of objects you need for your tests
63
- def self.new_user_with_colorblindness
64
- new_user { :favorite_color => nil }
40
+ ModelFactory.configuration do
41
+ default(User) do |m, i|
42
+ m.name = "Factory User #{i}"
43
+ m.email = "user#{i}@factory.ws"
65
44
  end
66
-
67
45
  end
68
46
 
69
- Then in your tests you use Factory methods to instantiate your test objects:
47
+ User.factory.create.name # => 'Factory User 1'
48
+ User.factory.create.email # => 'user2@factory.ws'
70
49
 
71
- # For most functional tests you can use create.
72
- def test_something
73
- user = Factory.create_user
74
- user.friends << Factory.create_user(:first_name => 'Frank')
75
- assert user.likes_frank?
76
- end
50
+ Defaults can be overriden on instance creation. By not specifying unimportant
51
+ values, the intention of your tests becomes clearer:
77
52
 
78
- # For unit tests you use new.
79
- def test_something_else
80
- user = Factory.new_user(:favorite_color => Factory.new_color(:name => 'blue'))
81
- assert user.likes_blue?
53
+ def test_welcome
54
+ user = ModelFactory[User].create(:name => 'bob')
55
+ assert_equal 'Welcome, bob!', user.welcome
82
56
  end
83
57
 
84
- # Assertions should not depend on default data, but it can be useful to create
85
- # factory methods that build objects with specific traits.
86
- def test_yet_something_else
87
- user = Factory.new_user_with_colorblindness
88
- assert !user.likes_blue?
89
- end
58
+ It's possible to configure named factories:
90
59
 
91
- You can also specify types of models in your calls to defaults, but be careful. This can
92
- easily start to become a lot like fixtures:
93
-
94
- module Factory
95
- extend ModelFactory
96
-
97
- default User, :joined {
98
- :first_name => 'Harry',
99
- :last_name => 'Manchester',
100
- :joined => true,
101
- :set_password => true,
102
- }
103
-
104
- default User, :unjoined {
105
- :first_name => 'Harry',
106
- :last_name => 'Manchester',
107
- :joined => false,
108
- :set_password => false,
109
- }
60
+ ModelFactory.configuration do
61
+ admin(User) do |m, i|
62
+ m.name = "Admin User #{i}"
63
+ m.admin = true
64
+ end
110
65
  end
111
66
 
112
- Then in your test:
67
+ User.factory.create_admin.admin # => true
113
68
 
114
- def test_something
115
- user1 = Factory.create_joined_user(:first_name => 'Bill')
116
- user2 = Factory.create_unjoined_user(:first_name => 'Sandy')
117
- assert user1.joined?
118
- assert !user2.joined?
119
- end
69
+ Named factories do not inherit anything from the default, so you'll still need to
70
+ provide enough to data to allow the creation of valid objects.
71
+
72
+ === A Note About Defaults
73
+
74
+ The purpose of default values is to generate valid instances, not to serve as
75
+ replacements for fixture data. When writing tests that use factory-generated
76
+ objects, it's important never to depend on default values in your test assertions.
77
+ If you depend on defaults in your tests they become more fragile and the intention
78
+ is harder to discern. Alway override values you care about when using factory objects.
120
79
 
121
80
  == Installing ModelFactory
122
81
 
@@ -124,6 +83,7 @@ Then in your test:
124
83
 
125
84
  == License
126
85
 
127
- Copyright (c) 2008 Justin Balthrop and Zack Hobson
86
+ Copyright (c) 2008, 2009 Justin Balthrop and Zack Hobson
87
+
128
88
  Published under The MIT License, see License.txt
129
89
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'hoe'
3
3
  $:.unshift(File.dirname(__FILE__) + "/lib")
4
- require 'model_factory/version'
4
+ require 'modelfactory/version'
5
5
 
6
6
  Hoe.new('ModelFactory', ModelFactory::VERSION::STRING) do |p|
7
7
  p.name = "modelfactory"
@@ -15,6 +15,7 @@ Hoe.new('ModelFactory', ModelFactory::VERSION::STRING) do |p|
15
15
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
16
16
  p.test_globs = ["test/**/*_test.rb"]
17
17
  p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
18
+ p.extra_dev_deps = ['active_record', 'mocha', 'thoughtbot-shoulda', 'sqlite3-ruby']
18
19
  end
19
20
 
20
21
 
@@ -1,4 +1,4 @@
1
- class FixtureConverter
1
+ class FixtureConverter # :nodoc:
2
2
  def initialize(opts = {})
3
3
  @body = []
4
4
  @header = []
@@ -94,4 +94,4 @@ private
94
94
  end
95
95
  ws + line
96
96
  end
97
- end
97
+ end
@@ -1,113 +1,13 @@
1
+ #
2
+ # This is the legacy modelfactory API.
3
+ # The current implementation is in lib/modelfactory.rb.
4
+ #
1
5
  require 'rubygems'
2
6
  require 'active_record'
7
+ require 'modelfactory/legacy'
3
8
 
4
9
  module ModelFactory
5
- def next_local_id # :nodoc:
6
- @max_id ||= 0
7
- return @max_id += 1
8
- end
9
-
10
- #
11
- # When specifying defaults, you should only provide only enough data that
12
- # the created instance is valid. If you want to include another factory
13
- # object as a dependency use the special method default_* instead of
14
- # create_* or new_*.
15
- #
16
- def default(class_type, *default_args)
17
- defaults = default_args.pop || {}
18
- prefix = default_args.first
19
- class_name = class_type.name.demodulize.underscore
20
- class_name = "#{prefix}_#{class_name}" if prefix
21
-
22
- (class << self; self; end).module_eval do
23
- define_method "create_#{class_name}" do |*args|
24
- attributes = args.first || {}
25
- create_instance(class_type, attributes, defaults)
26
- end
27
-
28
- define_method "new_#{class_name}" do |*args|
29
- attributes = args.first || {}
30
- new_instance(class_type, attributes, defaults)
31
- end
32
-
33
- define_method "default_#{class_name}" do |*args|
34
- attributes = args.first || {}
35
- default_closure(class_type, attributes, defaults)
36
- end
37
- end
38
- end
39
-
40
- def create_instance(class_type, attributes, defaults = {}) # :nodoc:
41
- attributes = instantiate_defaults(:create, defaults.merge(attributes))
42
- instance = class_type.create!(attributes)
43
- if update_protected_attributes(instance, attributes)
44
- instance.save
45
- end
46
- instance
47
- end
48
-
49
- def new_instance(class_type, attributes, defaults = {}) # :nodoc:
50
- attributes = instantiate_defaults(:new, defaults.merge(attributes))
51
- instance = class_type.new(attributes)
52
- instance.id = next_local_id
53
- update_protected_attributes(instance, attributes)
54
- instance
55
- end
56
-
57
- def default_closure(class_type, attributes, defaults = {}) # :nodoc:
58
- lambda do |create_or_new|
59
- case create_or_new
60
- when :new ; new_instance(class_type, attributes, defaults)
61
- when :create ; create_instance(class_type, attributes, defaults)
62
- end
63
- end
64
- end
65
-
66
- def instantiate_defaults(create_or_new, attributes) # :nodoc:
67
- attributes.each do |key, value|
68
- if value.is_a?(Proc)
69
- attributes[key] = value.arity == 0 ? value.call : value.call(create_or_new)
70
- end
71
- end
72
- attributes
73
- end
74
-
75
- def update_protected_attributes(instance, attributes) # :nodoc:
76
- modified = false
77
- protected_attrs = instance.class.protected_attributes
78
- protected_attrs = protected_attrs.to_set if protected_attrs
79
- accessible_attrs = instance.class.accessible_attributes
80
- accessible_attrs = accessible_attrs.to_set if accessible_attrs
81
-
82
- if protected_attrs or accessible_attrs
83
- attributes.each do |key, value|
84
- # Support symbols and strings.
85
- next if protected_attrs and (not protected_attrs.include?(key) or protected_attrs.include?(key.to_s))
86
- next if accessible_attrs and (accessible_attrs.include?(key) or accessible_attrs.include?(key.to_s))
87
- modified = true
88
- instance.send("#{key}=", value)
89
- end
90
- end
91
- return modified
92
- end
93
-
94
- # Any class methods of the form "new_some_type(attrs)" or "create_some_type(attrs)" will be converted to
95
- # "SomeType.new(attrs)" and "SomeType.create!(attrs)" respectively.
96
- # These basically function as though you'd used the 'default' directive with empty defaults.
97
- def method_missing(missing_method, attributes = {})
98
- if missing_method.to_s.match(/^(new|create|default)_([a-z][\w_]+)$/)
99
- method, class_name = $1, $2
100
- class_type = class_name.camelize.constantize
101
- case method
102
- when 'create'
103
- create_instance(class_type, attributes)
104
- when 'new'
105
- new_instance(class_type, attributes)
106
- when 'default'
107
- default_closure(class_type, attributes)
108
- end
109
- else
110
- raise NoMethodError, "no such method '#{missing_method}'"
111
- end
10
+ def self.extended(mod)
11
+ mod.extend(ModelFactory::Legacy)
112
12
  end
113
13
  end
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'modelfactory/factory'
4
+ require 'modelfactory/legacy'
5
+
6
+ ActiveRecord::Base.class_eval do
7
+ def self.factory ; ModelFactory[self] ; end
8
+ end
9
+
10
+ module ModelFactory
11
+ # Configure the factory singleton by passing a block.
12
+ #
13
+ # You can call this method multiple times. Each time you do so it will
14
+ # clear the existing configuration and reset the counters.
15
+ #
16
+ # You don't need to configure ModelFactory to use it.
17
+ def self.configure(&block)
18
+ @singleton = Wrapper.new(&block)
19
+ end
20
+
21
+ # Get the Factory for a given model class.
22
+ def self.[](klass)
23
+ @singleton ||= Wrapper.new
24
+ @singleton.wrap(klass)
25
+ end
26
+
27
+ # Enable legacy API compatibility.
28
+ def self.extended(mod) # :nodoc:
29
+ mod.extend(ModelFactory::Legacy)
30
+ end
31
+
32
+ # Singleton Factory wrapper class.
33
+ class Wrapper # :nodoc:
34
+ # Create a new FactoryConfiguration with the given block.
35
+ def initialize(&block)
36
+ @config = FactoryConfiguration.new(&block)
37
+ @factory = {}
38
+ end
39
+
40
+ # Wraps a given class in a configured Factory instance.
41
+ def wrap(klass)
42
+ @factory[klass] ||= Factory.new(klass, @config.class_opts[klass])
43
+ end
44
+ end
45
+
46
+ # Factory configuration class.
47
+ class FactoryConfiguration # :nodoc:
48
+ attr_reader :class_opts
49
+
50
+ def initialize(&block)
51
+ @class_opts = {}
52
+ instance_eval(&block) if block_given?
53
+ end
54
+
55
+ # All method calls set up a configuration named after the method.
56
+ def method_missing(method, klass, &block)
57
+ @class_opts[klass] ||= {}
58
+ @class_opts[klass][method] = block
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,59 @@
1
+ module ModelFactory # :nodoc:
2
+ # This API allows you to instantiate models.
3
+ class Factory # :nodoc:
4
+ def initialize(klass, opt)
5
+ @counter = 0
6
+ @class = klass
7
+ @options = opt || {}
8
+ end
9
+
10
+ def create(opt = {}, &block)
11
+ create_named(:default, opt, &block)
12
+ end
13
+
14
+ def new(opt = {}, &block)
15
+ new_named(:default, opt, &block)
16
+ end
17
+
18
+ def method_missing(method, opt = {}, &block)
19
+ case method.to_s
20
+ when /^create_(.+)$/
21
+ create_named($1.to_sym, opt, &block)
22
+ when /^new_(.+)$/
23
+ new_named($1.to_sym, opt, &block)
24
+ else
25
+ raise NameError, "no such method `#{method}'"
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def next_counter
32
+ @counter += 1
33
+ end
34
+
35
+ def new_named(name, opt = {}, &block)
36
+ instance = @class.new
37
+ if @options[name]
38
+ case @options[name].arity
39
+ when 2
40
+ @options[name].call(instance, next_counter) if @options[name]
41
+ else
42
+ @options[name].call(instance) if @options[name]
43
+ end
44
+ end
45
+ opt.each {|k,v| instance.send("#{k}=", v) }
46
+ yield instance if block_given?
47
+ instance
48
+ end
49
+
50
+ def create_named(name, opt = {}, &block)
51
+ instance = new_named(name, opt, &block)
52
+ instance.save!
53
+ instance.reload
54
+ instance
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,191 @@
1
+ module ModelFactory
2
+ # == ModelFactory Legacy API
3
+ #
4
+ # Put something like this in your test helper:
5
+ #
6
+ # require 'model_factory'
7
+ #
8
+ # module Factory
9
+ # extend ModelFactory
10
+ #
11
+ # # a default block accepts a class and a hash of default values
12
+ # default Color, {
13
+ # :name => 'chartreuse'
14
+ # }
15
+ #
16
+ # default User, {
17
+ # :first_name => 'Harry',
18
+ # :last_name => 'Manchester',
19
+ # :favorite_color => default_color
20
+ # }
21
+ #
22
+ # # Add class methods to create whatever kind of objects you need for your tests
23
+ # def self.new_user_with_colorblindness
24
+ # new_user { :favorite_color => nil }
25
+ # end
26
+ #
27
+ # end
28
+ #
29
+ # Then in your tests you use Factory methods to instantiate your test objects:
30
+ #
31
+ # # For most functional tests you can use create.
32
+ # def test_something
33
+ # user = Factory.create_user
34
+ # user.friends << Factory.create_user(:first_name => 'Frank')
35
+ # assert user.likes_frank?
36
+ # end
37
+ #
38
+ # # For unit tests you use new.
39
+ # def test_something_else
40
+ # user = Factory.new_user(:favorite_color => Factory.new_color(:name => 'blue'))
41
+ # assert user.likes_blue?
42
+ # end
43
+ #
44
+ # # Assertions should not depend on default data, but it can be useful to create
45
+ # # factory methods that build objects with specific traits.
46
+ # def test_yet_something_else
47
+ # user = Factory.new_user_with_colorblindness
48
+ # assert !user.likes_blue?
49
+ # end
50
+ #
51
+ # You can also specify types of models in your calls to defaults, but be careful. This can
52
+ # easily start to become a lot like fixtures:
53
+ #
54
+ # module Factory
55
+ # extend ModelFactory
56
+ #
57
+ # default User, :joined {
58
+ # :first_name => 'Harry',
59
+ # :last_name => 'Manchester',
60
+ # :joined => true,
61
+ # :set_password => true,
62
+ # }
63
+ #
64
+ # default User, :unjoined {
65
+ # :first_name => 'Harry',
66
+ # :last_name => 'Manchester',
67
+ # :joined => false,
68
+ # :set_password => false,
69
+ # }
70
+ # end
71
+ #
72
+ # Then in your test:
73
+ #
74
+ # def test_something
75
+ # user1 = Factory.create_joined_user(:first_name => 'Bill')
76
+ # user2 = Factory.create_unjoined_user(:first_name => 'Sandy')
77
+ # assert user1.joined?
78
+ # assert !user2.joined?
79
+ # end
80
+ #
81
+ module Legacy
82
+ def next_local_id # :nodoc:
83
+ @max_id ||= 0
84
+ return @max_id += 1
85
+ end
86
+
87
+ #
88
+ # When specifying defaults, you should only provide only enough data that
89
+ # the created instance is valid. If you want to include another factory
90
+ # object as a dependency use the special method default_* instead of
91
+ # create_* or new_*.
92
+ #
93
+ def default(class_type, *default_args)
94
+ defaults = default_args.pop || {}
95
+ prefix = default_args.first
96
+ class_name = class_type.name.demodulize.underscore
97
+ class_name = "#{prefix}_#{class_name}" if prefix
98
+
99
+ (class << self; self; end).module_eval do
100
+ define_method "create_#{class_name}" do |*args|
101
+ attributes = args.first || {}
102
+ create_instance(class_type, attributes, defaults)
103
+ end
104
+
105
+ define_method "new_#{class_name}" do |*args|
106
+ attributes = args.first || {}
107
+ new_instance(class_type, attributes, defaults)
108
+ end
109
+
110
+ define_method "default_#{class_name}" do |*args|
111
+ attributes = args.first || {}
112
+ default_closure(class_type, attributes, defaults)
113
+ end
114
+ end
115
+ end
116
+
117
+ def create_instance(class_type, attributes, defaults = {}) # :nodoc:
118
+ attributes = instantiate_defaults(:create, defaults.merge(attributes))
119
+ instance = class_type.create!(attributes)
120
+ if update_protected_attributes(instance, attributes)
121
+ instance.save
122
+ end
123
+ instance
124
+ end
125
+
126
+ def new_instance(class_type, attributes, defaults = {}) # :nodoc:
127
+ attributes = instantiate_defaults(:new, defaults.merge(attributes))
128
+ instance = class_type.new(attributes)
129
+ instance.id = next_local_id
130
+ update_protected_attributes(instance, attributes)
131
+ instance
132
+ end
133
+
134
+ def default_closure(class_type, attributes, defaults = {}) # :nodoc:
135
+ lambda do |create_or_new|
136
+ case create_or_new
137
+ when :new ; new_instance(class_type, attributes, defaults)
138
+ when :create ; create_instance(class_type, attributes, defaults)
139
+ end
140
+ end
141
+ end
142
+
143
+ def instantiate_defaults(create_or_new, attributes) # :nodoc:
144
+ attributes.each do |key, value|
145
+ if value.is_a?(Proc)
146
+ attributes[key] = value.arity == 0 ? value.call : value.call(create_or_new)
147
+ end
148
+ end
149
+ attributes
150
+ end
151
+
152
+ def update_protected_attributes(instance, attributes) # :nodoc:
153
+ modified = false
154
+ protected_attrs = instance.class.protected_attributes
155
+ protected_attrs = protected_attrs.to_set if protected_attrs
156
+ accessible_attrs = instance.class.accessible_attributes
157
+ accessible_attrs = accessible_attrs.to_set if accessible_attrs
158
+
159
+ if protected_attrs or accessible_attrs
160
+ attributes.each do |key, value|
161
+ # Support symbols and strings.
162
+ next if protected_attrs and (not protected_attrs.include?(key) or protected_attrs.include?(key.to_s))
163
+ next if accessible_attrs and (accessible_attrs.include?(key) or accessible_attrs.include?(key.to_s))
164
+ modified = true
165
+ instance.send("#{key}=", value)
166
+ end
167
+ end
168
+ return modified
169
+ end
170
+
171
+ # Any class methods of the form "new_some_type(attrs)" or "create_some_type(attrs)" will be converted to
172
+ # "SomeType.new(attrs)" and "SomeType.create!(attrs)" respectively.
173
+ # These basically function as though you'd used the 'default' directive with empty defaults.
174
+ def method_missing(missing_method, attributes = {})
175
+ if missing_method.to_s.match(/^(new|create|default)_([a-z][\w_]+)$/)
176
+ method, class_name = $1, $2
177
+ class_type = class_name.camelize.constantize
178
+ case method
179
+ when 'create'
180
+ create_instance(class_type, attributes)
181
+ when 'new'
182
+ new_instance(class_type, attributes)
183
+ when 'default'
184
+ default_closure(class_type, attributes)
185
+ end
186
+ else
187
+ raise NoMethodError, "no such method '#{missing_method}'"
188
+ end
189
+ end
190
+ end
191
+ end
@@ -2,7 +2,7 @@ module ModelFactory #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 8
5
- TINY = 1
5
+ TINY = 9
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,8 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table "widgets", :force => true do |t|
3
+ t.string "name"
4
+ t.decimal "price"
5
+ t.string "type"
6
+ end
7
+ end
8
+
@@ -0,0 +1,6 @@
1
+
2
+ class StrictWidget < Widget
3
+ validates_presence_of :name
4
+ validates_numericality_of :price
5
+ end
6
+
@@ -0,0 +1,4 @@
1
+
2
+ class Widget < ActiveRecord::Base
3
+ end
4
+
@@ -0,0 +1,142 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require File.dirname(__FILE__) + '/../lib/model_factory'
3
+
4
+ # The classes below are rough mocks of ActiveRecord::Base that only handle instantiation.
5
+
6
+ # This class has defaults defined.
7
+ class ModelFactoryTestDef
8
+ def self.protected_attributes; nil; end
9
+ def self.accessible_attributes; nil; end
10
+
11
+ attr_accessor :id, :nest, :bar, :baz
12
+ def initialize(opts = {})
13
+ opts.each do |k,v|
14
+ self.send("#{k}=", v)
15
+ end
16
+ end
17
+ end
18
+
19
+ # This class has no defaults defined.
20
+ class ModelFactoryTestNoDef < ModelFactoryTestDef; end
21
+
22
+ # This class has nested defaults defined.
23
+ class ModelFactoryTestNestDef < ModelFactoryTestDef; end
24
+
25
+ # This class has protected attributes.
26
+ class ModelFactoryTestProtected < ModelFactoryTestDef
27
+ def self.protected_attributes; [:baz]; end
28
+
29
+ def initialize(opts = {})
30
+ opts = opts.clone
31
+ opts.delete(:baz) # Simulate a protected attribute.
32
+ super(opts)
33
+ end
34
+ end
35
+
36
+ # This class has accessible attributes.
37
+ class ModelFactoryTestAccessible < ModelFactoryTestDef
38
+ def self.accessible_attributes; [:id, :nest, 'bar']; end
39
+
40
+ def initialize(opts = {})
41
+ opts = opts.clone
42
+ opts.delete(:baz) # Simulate a protected attribute.
43
+ super(opts)
44
+ end
45
+ end
46
+
47
+ # This is the testfactory class def with test defaults.
48
+ class ModelFactoryTestFactory
49
+ extend ModelFactory
50
+ default ModelFactoryTestDef, { :bar => 'baz' }
51
+ default ModelFactoryTestNestDef, { :nest => default_model_factory_test_def }
52
+ end
53
+
54
+ class ModelFactoryTest < Test::Unit::TestCase
55
+ context "legacy api compatibility" do
56
+ should "initialize protected attributes" do
57
+ m = ModelFactoryTestFactory.new_model_factory_test_protected(:baz => 4)
58
+ assert_equal 4, m.baz
59
+ end
60
+
61
+ should "initialize dynamic protected attributes" do
62
+ i = 1
63
+ m = ModelFactoryTestFactory.new_model_factory_test_protected(:bar => 3, :baz => lambda { i += 1 } )
64
+ assert_equal 2, m.baz
65
+ end
66
+
67
+ should "initialize accessible attributes" do
68
+ m = ModelFactoryTestFactory.new_model_factory_test_accessible(:baz => 4)
69
+ assert_equal 4, m.baz
70
+ end
71
+
72
+ should "initialize dynamic accessible attributes" do
73
+ i = 1
74
+ m = ModelFactoryTestFactory.new_model_factory_test_accessible(:bar => 3, :baz => lambda { i += 1 } )
75
+ assert_equal 2, m.baz
76
+ end
77
+
78
+ should "initialize with no arguments and nested defaults" do
79
+ m = ModelFactoryTestFactory.new_model_factory_test_nest_def
80
+ assert m.nest.id > 0
81
+ assert m.id > 0
82
+ end
83
+
84
+ should "intialize with arguments and nested defaults" do
85
+ m = ModelFactoryTestFactory.new_model_factory_test_nest_def(:bar => 'foo')
86
+ assert_equal 'foo', m.bar
87
+ assert m.nest.id > 0
88
+ assert m.id > 0
89
+ end
90
+
91
+ should "intialize with no arguments and explicit defaults" do
92
+ m = ModelFactoryTestFactory.new_model_factory_test_def
93
+ assert_equal 'baz', m.bar
94
+ assert m.id > 0
95
+ end
96
+
97
+ should "intialize with arguments and explicit defaults" do
98
+ m = ModelFactoryTestFactory.new_model_factory_test_def(:bar => 'foo')
99
+ assert_equal 'foo', m.bar
100
+ assert m.id > 0
101
+ end
102
+
103
+ should "create with arguments and explicit defaults" do
104
+ instance = ModelFactoryTestDef.new
105
+ ModelFactoryTestDef.expects(:create!).with(:bar => 'foo').returns(instance)
106
+ ModelFactoryTestFactory.create_model_factory_test_def(:bar => 'foo')
107
+ end
108
+
109
+ should "create with no arguments and explicit defaults" do
110
+ instance = ModelFactoryTestDef.new
111
+ ModelFactoryTestDef.expects(:create!).with(:bar => 'baz').returns(instance)
112
+ ModelFactoryTestFactory.create_model_factory_test_def
113
+ end
114
+
115
+ should "initialize with no arguments and no defaults" do
116
+ instance = ModelFactoryTestNoDef.new
117
+ ModelFactoryTestNoDef.expects(:new).returns(instance)
118
+ m = ModelFactoryTestFactory.new_model_factory_test_no_def
119
+ assert m.id > 0
120
+ end
121
+
122
+ should "initialize with arguments and no defaults" do
123
+ instance = ModelFactoryTestNoDef.new
124
+ ModelFactoryTestNoDef.expects(:new).with(:bar => 'foo').returns(instance)
125
+ m = ModelFactoryTestFactory.new_model_factory_test_no_def(:bar => 'foo')
126
+ assert m.id > 0
127
+ end
128
+
129
+ should "create with no arguments and no defaults" do
130
+ instance = ModelFactoryTestNoDef.new
131
+ ModelFactoryTestNoDef.expects(:create!).returns(instance)
132
+ ModelFactoryTestFactory.create_model_factory_test_no_def
133
+ end
134
+
135
+ should "create with arguments and no defaults" do
136
+ instance = ModelFactoryTestNoDef.new
137
+ ModelFactoryTestNoDef.expects(:create!).with(:bar => 'foo').returns(instance)
138
+ ModelFactoryTestFactory.create_model_factory_test_no_def(:bar => 'foo')
139
+ end
140
+ end
141
+ end
142
+
@@ -1,139 +1,86 @@
1
1
  require File.dirname(__FILE__) + '/test_helper'
2
+ require File.dirname(__FILE__) + '/../lib/modelfactory'
2
3
 
3
- # The classes below are rough mocks of ActiveRecord::Base that only handle instantiation.
4
-
5
- # This class has defaults defined.
6
- class ModelFactoryTestDef
7
- def self.protected_attributes; nil; end
8
- def self.accessible_attributes; nil; end
9
-
10
- attr_accessor :id, :nest, :bar, :baz
11
- def initialize(opts = {})
12
- opts.each do |k,v|
13
- self.send("#{k}=", v)
14
- end
15
- end
16
- end
17
-
18
- # This class has no defaults defined.
19
- class ModelFactoryTestNoDef < ModelFactoryTestDef; end
20
-
21
- # This class has nested defaults defined.
22
- class ModelFactoryTestNestDef < ModelFactoryTestDef; end
23
-
24
- # This class has protected attributes.
25
- class ModelFactoryTestProtected < ModelFactoryTestDef
26
- def self.protected_attributes; [:baz]; end
4
+ class ModelFactoryTest < Test::Unit::TestCase
27
5
 
28
- def initialize(opts = {})
29
- opts = opts.clone
30
- opts.delete(:baz) # Simulate a protected attribute.
31
- super(opts)
6
+ should "not instantiate when using new" do
7
+ assert Widget.factory.new.new_record?
32
8
  end
33
- end
34
-
35
- # This class has accessible attributes.
36
- class ModelFactoryTestAccessible < ModelFactoryTestDef
37
- def self.accessible_attributes; [:id, :nest, 'bar']; end
38
9
 
39
- def initialize(opts = {})
40
- opts = opts.clone
41
- opts.delete(:baz) # Simulate a protected attribute.
42
- super(opts)
10
+ should "instantiate when using create" do
11
+ assert !Widget.factory.create.new_record?
43
12
  end
44
- end
45
-
46
- # This is the testfactory class def with test defaults.
47
- class ModelFactoryTestFactory
48
- extend ModelFactory
49
- default ModelFactoryTestDef, { :bar => 'baz' }
50
- default ModelFactoryTestNestDef, { :nest => default_model_factory_test_def }
51
- end
52
13
 
53
- class ModelFactoryTest < Test::Unit::TestCase
54
- test "protected attributes" do
55
- m = ModelFactoryTestFactory.new_model_factory_test_protected(:baz => 4)
56
- assert_equal 4, m.baz
14
+ should "raise on creation of invalid records" do
15
+ assert_raises(ActiveRecord::RecordInvalid) { StrictWidget.factory.create }
57
16
  end
58
17
 
59
- test "dynamic protected attributes" do
60
- i = 1
61
- m = ModelFactoryTestFactory.new_model_factory_test_protected(:bar => 3, :baz => lambda { i += 1 } )
62
- assert_equal 2, m.baz
63
- end
64
-
65
- test "accessible attributes" do
66
- m = ModelFactoryTestFactory.new_model_factory_test_accessible(:baz => 4)
67
- assert_equal 4, m.baz
68
- end
18
+ context "with a specified default that uses automatic numbering" do
19
+ setup do
20
+ ModelFactory.configure do
21
+ default(Widget) {|w, i| w.price = i }
22
+ end
23
+ end
69
24
 
70
- test "dynamic accessible attributes" do
71
- i = 1
72
- m = ModelFactoryTestFactory.new_model_factory_test_accessible(:bar => 3, :baz => lambda { i += 1 } )
73
- assert_equal 2, m.baz
74
- end
75
-
76
- test "new with no arguments and nested defaults" do
77
- m = ModelFactoryTestFactory.new_model_factory_test_nest_def
78
- assert m.nest.id > 0
79
- assert m.id > 0
80
- end
81
-
82
- test "new with arguments and nested defaults" do
83
- m = ModelFactoryTestFactory.new_model_factory_test_nest_def(:bar => 'foo')
84
- assert_equal 'foo', m.bar
85
- assert m.nest.id > 0
86
- assert m.id > 0
87
- end
88
-
89
- test "new with no arguments and explicit defaults" do
90
- m = ModelFactoryTestFactory.new_model_factory_test_def
91
- assert_equal 'baz', m.bar
92
- assert m.id > 0
93
- end
94
-
95
- test "new with arguments and explicit defaults" do
96
- m = ModelFactoryTestFactory.new_model_factory_test_def(:bar => 'foo')
97
- assert_equal 'foo', m.bar
98
- assert m.id > 0
99
- end
100
-
101
- test "create with arguments and explicit defaults" do
102
- instance = ModelFactoryTestDef.new
103
- ModelFactoryTestDef.expects(:create!).with(:bar => 'foo').returns(instance)
104
- ModelFactoryTestFactory.create_model_factory_test_def(:bar => 'foo')
105
- end
106
-
107
- test "create with no arguments and explicit defaults" do
108
- instance = ModelFactoryTestDef.new
109
- ModelFactoryTestDef.expects(:create!).with(:bar => 'baz').returns(instance)
110
- ModelFactoryTestFactory.create_model_factory_test_def
111
- end
112
-
113
- test "new with no arguments and no defaults" do
114
- instance = ModelFactoryTestNoDef.new
115
- ModelFactoryTestNoDef.expects(:new).returns(instance)
116
- m = ModelFactoryTestFactory.new_model_factory_test_no_def
117
- assert m.id > 0
118
- end
25
+ should "start counting at 1 after configuration" do
26
+ assert_equal 1.0, Widget.factory.create.price
27
+ end
119
28
 
120
- test "new with arguments and no defaults" do
121
- instance = ModelFactoryTestNoDef.new
122
- ModelFactoryTestNoDef.expects(:new).with(:bar => 'foo').returns(instance)
123
- m = ModelFactoryTestFactory.new_model_factory_test_no_def(:bar => 'foo')
124
- assert m.id > 0
29
+ should "generate a unique sequence" do
30
+ w = []
31
+ 3.times { w << Widget.factory.create.price }
32
+ assert_equal w.uniq, w
33
+ end
125
34
  end
126
35
 
127
- test "create with no arguments and no defaults" do
128
- instance = ModelFactoryTestNoDef.new
129
- ModelFactoryTestNoDef.expects(:create!).returns(instance)
130
- ModelFactoryTestFactory.create_model_factory_test_no_def
36
+ context "with a specified default" do
37
+ setup do
38
+ ModelFactory.configure do
39
+ default(Widget) {|w| w.name = 'foobaz' }
40
+ end
41
+ end
42
+
43
+ should "initialize defaults with no arguments" do
44
+ assert_equal 'foobaz', Widget.factory.create.name
45
+ end
46
+
47
+ should "initialize defaults with an unspecified argument" do
48
+ assert_equal 'foobaz', Widget.factory.create(:price => 4.0).name
49
+ end
50
+
51
+ should "initialize with an unspecified argument" do
52
+ assert_equal 4, Widget.factory.create(:price => 4.0).price
53
+ end
131
54
  end
132
55
 
133
- test "create with arguments and no defaults" do
134
- instance = ModelFactoryTestNoDef.new
135
- ModelFactoryTestNoDef.expects(:create!).with(:bar => 'foo').returns(instance)
136
- ModelFactoryTestFactory.create_model_factory_test_no_def(:bar => 'foo')
56
+ context "with a named factory" do
57
+ setup do
58
+ ModelFactory.configure do
59
+ default(Widget) {|w| w.name = 'wubbo' }
60
+ favorite(Widget) {|w| w.name = 'foobaz' }
61
+ end
62
+ end
63
+
64
+ should "not apply named config to default" do
65
+ assert_equal 'wubbo', Widget.factory.create.name
66
+ end
67
+
68
+ should "not apply any config to unrecognized name" do
69
+ assert_equal nil, Widget.factory.create_emptyfoo.name
70
+ end
71
+
72
+ should "initialize defaults with no arguments" do
73
+ assert_equal 'foobaz', Widget.factory.create_favorite.name
74
+ end
75
+
76
+ should "initialize defaults with an unspecified argument" do
77
+ assert_equal 'foobaz', Widget.factory.create_favorite(:price => 4.0).name
78
+ end
79
+
80
+ should "initialize with an unspecified argument" do
81
+ assert_equal 4, Widget.factory.create_favorite(:price => 4.0).price
82
+ end
137
83
  end
138
84
  end
139
85
 
86
+
@@ -1,12 +1,22 @@
1
1
  require 'test/unit'
2
2
  require 'rubygems'
3
3
  require 'mocha'
4
- require File.dirname(__FILE__) + '/../lib/model_factory'
4
+ require 'shoulda'
5
5
 
6
- class << Test::Unit::TestCase
7
- def test(name, &block)
8
- test_name = "test_#{name.gsub(/[\s\W]/,'_')}"
9
- raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name
10
- define_method test_name, &block
11
- end
6
+ require 'active_record'
7
+ ActiveRecord::Base.establish_connection(
8
+ :database => ':memory:',
9
+ :adapter => 'sqlite3',
10
+ :timeout => 500
11
+ )
12
+
13
+ require 'active_record/fixtures'
14
+ require 'test/fixtures/schema.rb'
15
+ class Test::Unit::TestCase
16
+ FIXTURES_PATH = File.join(File.dirname(__FILE__), '/fixtures')
17
+ dep = defined?(ActiveSupport::Dependencies) ?
18
+ ActiveSupport::Dependencies :
19
+ ::Dependencies
20
+ dep.load_paths.unshift FIXTURES_PATH
12
21
  end
22
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modelfactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Balthrop
@@ -10,9 +10,49 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-08 00:00:00 -07:00
13
+ date: 2009-05-19 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: active_record
18
+ type: :development
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: mocha
28
+ type: :development
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ version:
36
+ - !ruby/object:Gem::Dependency
37
+ name: thoughtbot-shoulda
38
+ type: :development
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: sqlite3-ruby
48
+ type: :development
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
16
56
  - !ruby/object:Gem::Dependency
17
57
  name: hoe
18
58
  type: :development
@@ -42,12 +82,19 @@ files:
42
82
  - Rakefile
43
83
  - lib/fixture_converter.rb
44
84
  - lib/model_factory.rb
45
- - lib/model_factory/version.rb
85
+ - lib/modelfactory.rb
86
+ - lib/modelfactory/factory.rb
87
+ - lib/modelfactory/legacy.rb
88
+ - lib/modelfactory/version.rb
46
89
  - script/destroy
47
90
  - script/fixtures2factories
48
91
  - script/generate
49
92
  - script/txt2html
50
93
  - setup.rb
94
+ - test/fixtures/schema.rb
95
+ - test/fixtures/strict_widget.rb
96
+ - test/fixtures/widget.rb
97
+ - test/model_factory_legacy_test.rb
51
98
  - test/model_factory_test.rb
52
99
  - test/test_helper.rb
53
100
  has_rdoc: true
@@ -79,3 +126,4 @@ specification_version: 2
79
126
  summary: A replacement for fixtures.
80
127
  test_files:
81
128
  - test/model_factory_test.rb
129
+ - test/model_factory_legacy_test.rb