factory_girl 2.0.0.beta1 → 2.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Appraisals +12 -0
- data/{CONTRIBUTION_GUIDELINES.rdoc → CONTRIBUTION_GUIDELINES.md} +3 -3
- data/GETTING_STARTED.md +246 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +62 -0
- data/README.md +64 -0
- data/Rakefile +15 -30
- data/features/factory_girl_steps.feature +26 -0
- data/features/step_definitions/database_steps.rb +2 -0
- data/features/support/env.rb +0 -9
- data/features/support/factories.rb +15 -0
- data/features/support/test.db +0 -0
- data/lib/factory_girl.rb +2 -0
- data/lib/factory_girl/definition_proxy.rb +10 -43
- data/lib/factory_girl/factory.rb +48 -17
- data/lib/factory_girl/proxy.rb +3 -3
- data/lib/factory_girl/proxy/attributes_for.rb +1 -1
- data/lib/factory_girl/proxy/build.rb +3 -3
- data/lib/factory_girl/proxy/create.rb +6 -2
- data/lib/factory_girl/proxy/stub.rb +3 -3
- data/lib/factory_girl/registry.rb +59 -0
- data/lib/factory_girl/sequence.rb +23 -9
- data/lib/factory_girl/step_definitions.rb +16 -9
- data/lib/factory_girl/syntax/blueprint.rb +2 -2
- data/lib/factory_girl/syntax/default.rb +5 -3
- data/lib/factory_girl/syntax/generate.rb +6 -6
- data/lib/factory_girl/syntax/make.rb +2 -2
- data/lib/factory_girl/syntax/methods.rb +75 -0
- data/lib/factory_girl/syntax/sham.rb +2 -2
- data/lib/factory_girl/syntax/vintage.rb +16 -79
- data/lib/factory_girl/version.rb +1 -1
- data/spec/acceptance/acceptance_helper.rb +7 -12
- data/spec/acceptance/attribute_aliases_spec.rb +26 -0
- data/spec/acceptance/attributes_for_spec.rb +48 -0
- data/spec/acceptance/build_spec.rb +35 -0
- data/spec/acceptance/build_stubbed_spec.rb +79 -0
- data/spec/acceptance/callbacks_spec.rb +42 -0
- data/spec/acceptance/create_spec.rb +67 -0
- data/spec/acceptance/default_strategy_spec.rb +27 -0
- data/spec/acceptance/definition_spec.rb +28 -0
- data/spec/acceptance/parent_spec.rb +39 -0
- data/spec/acceptance/sequence_spec.rb +32 -0
- data/spec/acceptance/syntax/blueprint_spec.rb +7 -5
- data/spec/acceptance/syntax/generate_spec.rb +10 -4
- data/spec/acceptance/syntax/make_spec.rb +7 -4
- data/spec/acceptance/syntax/sham_spec.rb +15 -8
- data/spec/acceptance/syntax/vintage_spec.rb +57 -17
- data/spec/factory_girl/attribute/dynamic_spec.rb +1 -1
- data/spec/factory_girl/definition_proxy_spec.rb +13 -11
- data/spec/factory_girl/factory_spec.rb +29 -52
- data/spec/factory_girl/find_definitions_spec.rb +34 -23
- data/spec/factory_girl/proxy/attributes_for_spec.rb +6 -6
- data/spec/factory_girl/proxy/build_spec.rb +4 -4
- data/spec/factory_girl/proxy/create_spec.rb +11 -3
- data/spec/factory_girl/proxy/stub_spec.rb +6 -6
- data/spec/factory_girl/proxy_spec.rb +1 -1
- data/spec/factory_girl/registry_spec.rb +92 -0
- data/spec/factory_girl/sequence_spec.rb +65 -8
- data/spec/spec_helper.rb +75 -29
- metadata +66 -43
- data/README.rdoc +0 -282
- data/spec/acceptance/acceptance_spec.rb +0 -288
- data/spec/acceptance/models.rb +0 -48
@@ -123,3 +123,29 @@ Feature: Use step definitions generated by factories
|
|
123
123
|
And 2 categories exist
|
124
124
|
And 2 categories exist with a name of "Future"
|
125
125
|
Then there should be 6 categories
|
126
|
+
|
127
|
+
Scenario: create a post with an existing category group
|
128
|
+
Given the following category exists:
|
129
|
+
| ID | name | category group |
|
130
|
+
| 123 | fiction | Name: books |
|
131
|
+
And the following post exists:
|
132
|
+
| Title | Author | Category |
|
133
|
+
| a title | Name: Joe | Category Group: Name: books |
|
134
|
+
Then I should find the following for the last post:
|
135
|
+
| title | category_id |
|
136
|
+
| a title | 123 |
|
137
|
+
|
138
|
+
Scenario: create a post with an existing category group and a new category
|
139
|
+
Given the following category group exists:
|
140
|
+
| ID | name |
|
141
|
+
| 456 | books |
|
142
|
+
And the following post exists:
|
143
|
+
| Title | Author | Category |
|
144
|
+
| a title | Name: Joe | Category Group: Name: books |
|
145
|
+
Then I should find the following for the last post:
|
146
|
+
| title |
|
147
|
+
| a title |
|
148
|
+
And I should find the following for the last category:
|
149
|
+
| category_group_id |
|
150
|
+
| 456 |
|
151
|
+
|
data/features/support/env.rb
CHANGED
@@ -2,14 +2,5 @@ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
|
2
2
|
|
3
3
|
$: << File.join(PROJECT_ROOT, 'lib')
|
4
4
|
|
5
|
-
case ENV['RAILS_VERSION']
|
6
|
-
when '2.1' then
|
7
|
-
gem 'activerecord', '~>2.1.0'
|
8
|
-
when '3.0' then
|
9
|
-
gem 'activerecord', '~>3.0.0'
|
10
|
-
else
|
11
|
-
gem 'activerecord', '~>2.3.0'
|
12
|
-
end
|
13
|
-
|
14
5
|
require 'active_record'
|
15
6
|
require 'factory_girl'
|
@@ -12,7 +12,12 @@ class CreateSchema < ActiveRecord::Migration
|
|
12
12
|
t.string :body
|
13
13
|
end
|
14
14
|
|
15
|
+
create_table :category_groups, :force => true do |t|
|
16
|
+
t.string :name
|
17
|
+
end
|
18
|
+
|
15
19
|
create_table :categories, :force => true do |t|
|
20
|
+
t.integer :category_group_id
|
16
21
|
t.string :name
|
17
22
|
end
|
18
23
|
|
@@ -28,7 +33,11 @@ CreateSchema.suppress_messages { CreateSchema.migrate(:up) }
|
|
28
33
|
class User < ActiveRecord::Base
|
29
34
|
end
|
30
35
|
|
36
|
+
class CategoryGroup < ActiveRecord::Base
|
37
|
+
end
|
38
|
+
|
31
39
|
class Category < ActiveRecord::Base
|
40
|
+
belongs_to :category_group
|
32
41
|
end
|
33
42
|
|
34
43
|
class Post < ActiveRecord::Base
|
@@ -48,6 +57,11 @@ end
|
|
48
57
|
|
49
58
|
Factory.define :category do |f|
|
50
59
|
f.name "programming"
|
60
|
+
f.association :category_group
|
61
|
+
end
|
62
|
+
|
63
|
+
Factory.define :category_group do |f|
|
64
|
+
f.name "tecnhology"
|
51
65
|
end
|
52
66
|
|
53
67
|
Factory.define :post do |f|
|
@@ -60,3 +74,4 @@ Factory.define :non_active_record do |f|
|
|
60
74
|
end
|
61
75
|
|
62
76
|
require 'factory_girl/step_definitions'
|
77
|
+
|
data/features/support/test.db
CHANGED
Binary file
|
data/lib/factory_girl.rb
CHANGED
@@ -3,6 +3,7 @@ require 'factory_girl/proxy/build'
|
|
3
3
|
require 'factory_girl/proxy/create'
|
4
4
|
require 'factory_girl/proxy/attributes_for'
|
5
5
|
require 'factory_girl/proxy/stub'
|
6
|
+
require 'factory_girl/registry'
|
6
7
|
require 'factory_girl/factory'
|
7
8
|
require 'factory_girl/attribute'
|
8
9
|
require 'factory_girl/attribute/static'
|
@@ -12,6 +13,7 @@ require 'factory_girl/attribute/callback'
|
|
12
13
|
require 'factory_girl/sequence'
|
13
14
|
require 'factory_girl/aliases'
|
14
15
|
require 'factory_girl/definition_proxy'
|
16
|
+
require 'factory_girl/syntax/methods'
|
15
17
|
require 'factory_girl/syntax/default'
|
16
18
|
require 'factory_girl/syntax/vintage'
|
17
19
|
require 'factory_girl/find_definitions'
|
@@ -22,7 +22,7 @@ module FactoryGirl
|
|
22
22
|
#
|
23
23
|
# Arguments:
|
24
24
|
# * name: +Symbol+ or +String+
|
25
|
-
# The name of this attribute. This will be assigned using
|
25
|
+
# The name of this attribute. This will be assigned using "name=" for
|
26
26
|
# generated instances.
|
27
27
|
# * value: +Object+
|
28
28
|
# If no block is given, this value will be used for this attribute.
|
@@ -59,7 +59,7 @@ module FactoryGirl
|
|
59
59
|
# or association with the same name. This means that:
|
60
60
|
#
|
61
61
|
# factory :user do
|
62
|
-
# email {
|
62
|
+
# email { create(:email) }
|
63
63
|
# association :account
|
64
64
|
# end
|
65
65
|
#
|
@@ -73,11 +73,7 @@ module FactoryGirl
|
|
73
73
|
# are equivilent.
|
74
74
|
def method_missing(name, *args, &block)
|
75
75
|
if args.empty? && block.nil?
|
76
|
-
|
77
|
-
add_attribute(name) { sequence.next }
|
78
|
-
else
|
79
|
-
association(name)
|
80
|
-
end
|
76
|
+
association(name)
|
81
77
|
else
|
82
78
|
add_attribute(name, *args, &block)
|
83
79
|
end
|
@@ -95,13 +91,13 @@ module FactoryGirl
|
|
95
91
|
# sequence(:email) { |n| "person#{n}@example.com" }
|
96
92
|
#
|
97
93
|
# factory :user do
|
98
|
-
# email {
|
94
|
+
# email { FactoryGirl.create(:email) }
|
99
95
|
# end
|
100
96
|
#
|
101
97
|
# Except that no globally available sequence will be defined.
|
102
98
|
def sequence(name, start_value = 1, &block)
|
103
|
-
sequence = Sequence.new(start_value, &block)
|
104
|
-
add_attribute(name) { sequence.
|
99
|
+
sequence = Sequence.new(name, start_value, &block)
|
100
|
+
add_attribute(name) { sequence.run }
|
105
101
|
end
|
106
102
|
|
107
103
|
# Adds an attribute that builds an association. The associated instance will
|
@@ -132,39 +128,6 @@ module FactoryGirl
|
|
132
128
|
@factory.define_attribute(Attribute::Association.new(name, factory_name, options))
|
133
129
|
end
|
134
130
|
|
135
|
-
# Registers an alias for this factory using the given name.
|
136
|
-
#
|
137
|
-
# Arguments:
|
138
|
-
# * name: +Symbol+
|
139
|
-
# The name of the alias.
|
140
|
-
#
|
141
|
-
# Example:
|
142
|
-
#
|
143
|
-
# factory :user do
|
144
|
-
# aliased_as :author
|
145
|
-
# end
|
146
|
-
#
|
147
|
-
# Factory(:author).class
|
148
|
-
# # => User
|
149
|
-
#
|
150
|
-
# Because an attribute defined without a value or block will build an
|
151
|
-
# association with the same name, this allows associations to be defined
|
152
|
-
# without factories, such as:
|
153
|
-
#
|
154
|
-
# factory :user do
|
155
|
-
# aliased_as :author
|
156
|
-
# end
|
157
|
-
#
|
158
|
-
# factory :post do
|
159
|
-
# author
|
160
|
-
# end
|
161
|
-
#
|
162
|
-
# Factory(:post).author.class
|
163
|
-
# # => User
|
164
|
-
def aliased_as(name)
|
165
|
-
FactoryGirl.register_factory(@factory, :as => name)
|
166
|
-
end
|
167
|
-
|
168
131
|
def after_build(&block)
|
169
132
|
@factory.add_callback(:after_build, &block)
|
170
133
|
end
|
@@ -176,5 +139,9 @@ module FactoryGirl
|
|
176
139
|
def after_stub(&block)
|
177
140
|
@factory.add_callback(:after_stub, &block)
|
178
141
|
end
|
142
|
+
|
143
|
+
def to_create(&block)
|
144
|
+
@factory.to_create(&block)
|
145
|
+
end
|
179
146
|
end
|
180
147
|
end
|
data/lib/factory_girl/factory.rb
CHANGED
@@ -1,20 +1,14 @@
|
|
1
1
|
module FactoryGirl
|
2
|
-
|
3
|
-
|
2
|
+
def self.factories
|
3
|
+
puts "WARNING: FactoryGirl.factories is deprecated."
|
4
|
+
puts "Use FactoryGirl.registry instead."
|
5
|
+
registry
|
4
6
|
end
|
5
7
|
|
6
|
-
self.factories = {}
|
7
|
-
|
8
8
|
def self.factory_by_name(name)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def self.register_factory(factory, options = {})
|
13
|
-
name = options[:as] || factory.name
|
14
|
-
if self.factories[name]
|
15
|
-
raise DuplicateDefinitionError, "Factory already defined: #{name}"
|
16
|
-
end
|
17
|
-
self.factories[name] = factory
|
9
|
+
puts "WARNING: FactoryGirl.factory_by_name is deprecated."
|
10
|
+
puts "Use FactoryGirl.find instead."
|
11
|
+
registry.find(name)
|
18
12
|
end
|
19
13
|
|
20
14
|
# Raised when a factory is defined that attempts to instantiate itself.
|
@@ -89,7 +83,7 @@ module FactoryGirl
|
|
89
83
|
@attributes << Attribute::Callback.new(name.to_sym, block)
|
90
84
|
end
|
91
85
|
|
92
|
-
def run
|
86
|
+
def run(proxy_class, overrides) #:nodoc:
|
93
87
|
proxy = proxy_class.new(build_class)
|
94
88
|
overrides = symbolize_keys(overrides)
|
95
89
|
overrides.each {|attr, val| proxy.set(attr, val) }
|
@@ -99,7 +93,7 @@ module FactoryGirl
|
|
99
93
|
attribute.add_to(proxy)
|
100
94
|
end
|
101
95
|
end
|
102
|
-
proxy.result
|
96
|
+
proxy.result(@to_create_block)
|
103
97
|
end
|
104
98
|
|
105
99
|
def human_name(*args, &block)
|
@@ -110,6 +104,39 @@ module FactoryGirl
|
|
110
104
|
attributes.select {|attribute| attribute.is_a?(Attribute::Association) }
|
111
105
|
end
|
112
106
|
|
107
|
+
# Names for this factory, including aliases.
|
108
|
+
#
|
109
|
+
# Example:
|
110
|
+
#
|
111
|
+
# factory :user, :aliases => [:author] do
|
112
|
+
# # ...
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# FactoryGirl.create(:author).class
|
116
|
+
# # => User
|
117
|
+
#
|
118
|
+
# Because an attribute defined without a value or block will build an
|
119
|
+
# association with the same name, this allows associations to be defined
|
120
|
+
# without factories, such as:
|
121
|
+
#
|
122
|
+
# factory :user, :aliases => [:author] do
|
123
|
+
# # ...
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# factory :post do
|
127
|
+
# author
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# FactoryGirl.create(:post).author.class
|
131
|
+
# # => User
|
132
|
+
def names
|
133
|
+
[name] + (@options[:aliases] || [])
|
134
|
+
end
|
135
|
+
|
136
|
+
def to_create(&block)
|
137
|
+
@to_create_block = block
|
138
|
+
end
|
139
|
+
|
113
140
|
private
|
114
141
|
|
115
142
|
def class_for (class_or_to_s)
|
@@ -136,11 +163,15 @@ module FactoryGirl
|
|
136
163
|
end
|
137
164
|
|
138
165
|
def assert_valid_options(options)
|
139
|
-
invalid_keys = options.keys - [:class, :parent, :default_strategy]
|
166
|
+
invalid_keys = options.keys - [:class, :parent, :default_strategy, :aliases]
|
140
167
|
unless invalid_keys == []
|
141
168
|
raise ArgumentError, "Unknown arguments: #{invalid_keys.inspect}"
|
142
169
|
end
|
143
|
-
|
170
|
+
if options[:default_strategy]
|
171
|
+
assert_valid_strategy(options[:default_strategy])
|
172
|
+
puts "WARNING: default_strategy is deprecated."
|
173
|
+
puts "Override to_create if you need to prevent a call to #save!."
|
174
|
+
end
|
144
175
|
end
|
145
176
|
|
146
177
|
def assert_valid_strategy(strategy)
|
data/lib/factory_girl/proxy.rb
CHANGED
@@ -56,11 +56,11 @@ module FactoryGirl
|
|
56
56
|
# end
|
57
57
|
#
|
58
58
|
# # Builds (but doesn't save) a Post and a User
|
59
|
-
#
|
59
|
+
# FactoryGirl.build(:post)
|
60
60
|
#
|
61
61
|
# # Builds and saves a User, builds a Post, assigns the User to the
|
62
62
|
# # author association, and saves the User.
|
63
|
-
#
|
63
|
+
# FactoryGirl.create(:post)
|
64
64
|
#
|
65
65
|
def association(name, overrides = {})
|
66
66
|
nil
|
@@ -70,7 +70,7 @@ module FactoryGirl
|
|
70
70
|
get(method)
|
71
71
|
end
|
72
72
|
|
73
|
-
def result
|
73
|
+
def result(to_create)
|
74
74
|
raise NotImplementedError, "Strategies must return a result"
|
75
75
|
end
|
76
76
|
end
|
@@ -14,16 +14,16 @@ module FactoryGirl
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def associate(name, factory_name, overrides)
|
17
|
-
factory = FactoryGirl.
|
17
|
+
factory = FactoryGirl.find(factory_name)
|
18
18
|
set(name, factory.run(Proxy::Create, overrides))
|
19
19
|
end
|
20
20
|
|
21
21
|
def association(factory_name, overrides = {})
|
22
|
-
factory = FactoryGirl.
|
22
|
+
factory = FactoryGirl.find(factory_name)
|
23
23
|
factory.run(Proxy::Create, overrides)
|
24
24
|
end
|
25
25
|
|
26
|
-
def result
|
26
|
+
def result(to_create)
|
27
27
|
run_callbacks(:after_build)
|
28
28
|
@instance
|
29
29
|
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
module FactoryGirl
|
2
2
|
class Proxy #:nodoc:
|
3
3
|
class Create < Build #:nodoc:
|
4
|
-
def result
|
4
|
+
def result(to_create)
|
5
5
|
run_callbacks(:after_build)
|
6
|
-
|
6
|
+
if to_create
|
7
|
+
to_create.call(@instance)
|
8
|
+
else
|
9
|
+
@instance.save!
|
10
|
+
end
|
7
11
|
run_callbacks(:after_create)
|
8
12
|
@instance
|
9
13
|
end
|
@@ -46,16 +46,16 @@ module FactoryGirl
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def associate(name, factory_name, overrides)
|
49
|
-
factory = FactoryGirl.
|
49
|
+
factory = FactoryGirl.find(factory_name)
|
50
50
|
set(name, factory.run(Proxy::Stub, overrides))
|
51
51
|
end
|
52
52
|
|
53
53
|
def association(factory_name, overrides = {})
|
54
|
-
factory = FactoryGirl.
|
54
|
+
factory = FactoryGirl.find(factory_name)
|
55
55
|
factory.run(Proxy::Stub, overrides)
|
56
56
|
end
|
57
57
|
|
58
|
-
def result
|
58
|
+
def result(to_create)
|
59
59
|
run_callbacks(:after_stub)
|
60
60
|
@instance
|
61
61
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module FactoryGirl
|
2
|
+
class Registry
|
3
|
+
def initialize
|
4
|
+
@items = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def add(item)
|
8
|
+
item.names.each { |name| add_as(name, item) }
|
9
|
+
item
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(name)
|
13
|
+
@items[name.to_sym] or raise ArgumentError.new("Not registered: #{name.to_s}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
@items.each(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](name)
|
21
|
+
find(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def registered?(name)
|
25
|
+
@items.key?(name.to_sym)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def add_as(name, item)
|
31
|
+
if registered?(name)
|
32
|
+
raise DuplicateDefinitionError, "Already defined: #{name}"
|
33
|
+
else
|
34
|
+
@items[name.to_sym] = item
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.register(item)
|
40
|
+
registry.add(item)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.registered?(name)
|
44
|
+
registry.registered?(name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.find(name)
|
48
|
+
registry.find(name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.registry
|
52
|
+
@registry ||= Registry.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.registry=(registry)
|
56
|
+
@registry = registry
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|