modelfactory 0.8.1 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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