factory_girl 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +1 -1
- data/CONTRIBUTION_GUIDELINES.md +1 -1
- data/Changelog +16 -3
- data/GETTING_STARTED.md +22 -2
- data/Gemfile.lock +1 -1
- data/Rakefile +11 -15
- data/gemfiles/2.1.gemfile.lock +1 -1
- data/gemfiles/2.3.gemfile.lock +1 -1
- data/gemfiles/3.0.gemfile.lock +1 -1
- data/gemfiles/3.1.gemfile.lock +1 -1
- data/lib/factory_girl.rb +8 -3
- data/lib/factory_girl/attribute.rb +8 -0
- data/lib/factory_girl/attribute/dynamic.rb +1 -5
- data/lib/factory_girl/attribute/sequence.rb +1 -5
- data/lib/factory_girl/attribute/static.rb +1 -5
- data/lib/factory_girl/attribute_list.rb +18 -44
- data/lib/factory_girl/callback.rb +5 -0
- data/lib/factory_girl/declaration.rb +3 -0
- data/lib/factory_girl/declaration/association.rb +8 -0
- data/lib/factory_girl/declaration/dynamic.rb +9 -0
- data/lib/factory_girl/declaration/implicit.rb +11 -2
- data/lib/factory_girl/declaration/static.rb +9 -0
- data/lib/factory_girl/declaration_list.rb +48 -0
- data/lib/factory_girl/definition.rb +62 -0
- data/lib/factory_girl/definition_proxy.rb +11 -11
- data/lib/factory_girl/factory.rb +100 -111
- data/lib/factory_girl/null_factory.rb +15 -0
- data/lib/factory_girl/proxy.rb +14 -9
- data/lib/factory_girl/proxy/attributes_for.rb +2 -3
- data/lib/factory_girl/proxy/build.rb +12 -20
- data/lib/factory_girl/proxy/create.rb +0 -6
- data/lib/factory_girl/proxy/stub.rb +4 -10
- data/lib/factory_girl/registry.rb +4 -3
- data/lib/factory_girl/step_definitions.rb +1 -1
- data/lib/factory_girl/syntax/default.rb +3 -4
- data/lib/factory_girl/syntax/methods.rb +38 -16
- data/lib/factory_girl/trait.rb +13 -21
- data/lib/factory_girl/version.rb +1 -1
- data/spec/acceptance/modify_factories_spec.rb +1 -1
- data/spec/acceptance/traits_spec.rb +87 -1
- data/spec/factory_girl/attribute/dynamic_spec.rb +1 -1
- data/spec/factory_girl/attribute_list_spec.rb +9 -58
- data/spec/factory_girl/declaration_list_spec.rb +71 -0
- data/spec/factory_girl/definition_proxy_spec.rb +135 -139
- data/spec/factory_girl/definition_spec.rb +81 -0
- data/spec/factory_girl/factory_spec.rb +42 -17
- data/spec/factory_girl/null_factory_spec.rb +12 -0
- data/spec/factory_girl/proxy/build_spec.rb +1 -24
- data/spec/factory_girl/proxy/create_spec.rb +14 -11
- data/spec/factory_girl/proxy_spec.rb +23 -40
- data/spec/factory_girl/registry_spec.rb +4 -3
- data/spec/spec_helper.rb +2 -0
- data/spec/support/matchers/callback.rb +9 -0
- data/spec/support/matchers/declaration.rb +71 -0
- data/spec/support/matchers/delegate.rb +44 -0
- data/spec/support/matchers/trait.rb +9 -0
- data/spec/support/shared_examples/proxy.rb +4 -5
- metadata +191 -115
@@ -0,0 +1,15 @@
|
|
1
|
+
module FactoryGirl
|
2
|
+
class NullFactory
|
3
|
+
attr_reader :definition
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@definition = Definition.new
|
7
|
+
end
|
8
|
+
|
9
|
+
delegate :defined_traits, :callbacks, :attributes, :to => :definition
|
10
|
+
|
11
|
+
def compile; end
|
12
|
+
def default_strategy; end
|
13
|
+
def class_name; end
|
14
|
+
end
|
15
|
+
end
|
data/lib/factory_girl/proxy.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
require "active_support/core_ext/hash/except"
|
2
|
+
|
1
3
|
module FactoryGirl
|
2
4
|
class Proxy #:nodoc:
|
5
|
+
def initialize(klass, callbacks = [])
|
6
|
+
@callbacks = callbacks.inject({}) do |result, callback|
|
7
|
+
result[callback.name] ||= []
|
8
|
+
result[callback.name] << callback
|
9
|
+
result
|
10
|
+
end
|
3
11
|
|
4
|
-
attr_reader :callbacks
|
5
|
-
|
6
|
-
def initialize(klass)
|
7
|
-
@callbacks = {}
|
8
12
|
@ignored_attributes = {}
|
9
13
|
end
|
10
14
|
|
@@ -21,11 +25,6 @@ module FactoryGirl
|
|
21
25
|
def associate(name, factory, attributes)
|
22
26
|
end
|
23
27
|
|
24
|
-
def add_callback(callback)
|
25
|
-
@callbacks[callback.name] ||= []
|
26
|
-
@callbacks[callback.name] << callback
|
27
|
-
end
|
28
|
-
|
29
28
|
def run_callbacks(name)
|
30
29
|
if @callbacks[name]
|
31
30
|
@callbacks[name].each do |callback|
|
@@ -76,5 +75,11 @@ module FactoryGirl
|
|
76
75
|
def result(to_create)
|
77
76
|
raise NotImplementedError, "Strategies must return a result"
|
78
77
|
end
|
78
|
+
|
79
|
+
def self.ensure_strategy_exists!(strategy)
|
80
|
+
unless Proxy.const_defined? strategy.to_s.camelize
|
81
|
+
raise ArgumentError, "Unknown strategy: #{strategy}"
|
82
|
+
end
|
83
|
+
end
|
79
84
|
end
|
80
85
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module FactoryGirl
|
2
2
|
class Proxy #:nodoc:
|
3
3
|
class Build < Proxy #:nodoc:
|
4
|
-
def initialize(klass)
|
5
|
-
super
|
4
|
+
def initialize(klass, callbacks = [])
|
5
|
+
super
|
6
6
|
@instance = klass.new
|
7
7
|
end
|
8
8
|
|
@@ -19,19 +19,13 @@ module FactoryGirl
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def associate(name, factory_name, overrides)
|
22
|
-
|
23
|
-
factory = FactoryGirl.factory_by_name(factory_name)
|
24
|
-
set(name, factory.run(method, remove_method(overrides)))
|
22
|
+
set(name, association(factory_name, overrides))
|
25
23
|
end
|
26
24
|
|
27
25
|
def association(factory_name, overrides = {})
|
28
26
|
method = get_method(overrides[:method])
|
29
27
|
factory = FactoryGirl.factory_by_name(factory_name)
|
30
|
-
factory.run(method,
|
31
|
-
end
|
32
|
-
|
33
|
-
def remove_method(overrides)
|
34
|
-
overrides.dup.delete_if {|key, value| key == :method}
|
28
|
+
factory.run(method, overrides.except(:method))
|
35
29
|
end
|
36
30
|
|
37
31
|
def result(to_create)
|
@@ -39,18 +33,16 @@ module FactoryGirl
|
|
39
33
|
@instance
|
40
34
|
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
36
|
+
private
|
37
|
+
|
38
|
+
def get_method(method)
|
39
|
+
case method
|
40
|
+
when :build then Proxy::Build
|
41
|
+
when :create then Proxy::Create
|
42
|
+
when nil then Proxy::Create
|
43
|
+
else raise "unrecognized method #{method}"
|
50
44
|
end
|
51
45
|
end
|
52
|
-
|
53
|
-
alias_method :get_method, :parse_method
|
54
46
|
end
|
55
47
|
end
|
56
48
|
end
|
@@ -11,12 +11,6 @@ module FactoryGirl
|
|
11
11
|
run_callbacks(:after_create)
|
12
12
|
@instance
|
13
13
|
end
|
14
|
-
|
15
|
-
def get_method(method_string)
|
16
|
-
# Leaving this as Proxy::Build in the :method => :build case
|
17
|
-
# is a bit strange, but does it have any user-visible behaviors?
|
18
|
-
parse_method(method_string)
|
19
|
-
end
|
20
14
|
end
|
21
15
|
end
|
22
16
|
end
|
@@ -3,10 +3,9 @@ module FactoryGirl
|
|
3
3
|
class Stub < Proxy #:nodoc:
|
4
4
|
@@next_id = 1000
|
5
5
|
|
6
|
-
def initialize(klass)
|
7
|
-
super
|
6
|
+
def initialize(klass, callbacks = [])
|
7
|
+
super
|
8
8
|
@instance = klass.new
|
9
|
-
@ignored_attributes = {}
|
10
9
|
@instance.id = next_id
|
11
10
|
@instance.instance_eval do
|
12
11
|
def persisted?
|
@@ -60,17 +59,12 @@ module FactoryGirl
|
|
60
59
|
end
|
61
60
|
|
62
61
|
def associate(name, factory_name, overrides)
|
63
|
-
|
64
|
-
set(name, factory.run(Proxy::Stub, remove_method(overrides)))
|
62
|
+
set(name, association(factory_name, overrides))
|
65
63
|
end
|
66
64
|
|
67
65
|
def association(factory_name, overrides = {})
|
68
66
|
factory = FactoryGirl.factory_by_name(factory_name)
|
69
|
-
factory.run(Proxy::Stub,
|
70
|
-
end
|
71
|
-
|
72
|
-
def remove_method(overrides)
|
73
|
-
overrides.dup.delete_if {|key, value| key == :method}
|
67
|
+
factory.run(Proxy::Stub, overrides.except(:method))
|
74
68
|
end
|
75
69
|
|
76
70
|
def result(to_create)
|
@@ -2,7 +2,8 @@ module FactoryGirl
|
|
2
2
|
class Registry
|
3
3
|
include Enumerable
|
4
4
|
|
5
|
-
def initialize
|
5
|
+
def initialize(name)
|
6
|
+
@name = name
|
6
7
|
@items = {}
|
7
8
|
end
|
8
9
|
|
@@ -12,7 +13,7 @@ module FactoryGirl
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def find(name)
|
15
|
-
@items[name.to_sym] or raise ArgumentError.new("
|
16
|
+
@items[name.to_sym] or raise ArgumentError.new("#{@name} not registered: #{name.to_s}")
|
16
17
|
end
|
17
18
|
|
18
19
|
def each(&block)
|
@@ -35,7 +36,7 @@ module FactoryGirl
|
|
35
36
|
|
36
37
|
def add_as(name, item)
|
37
38
|
if registered?(name)
|
38
|
-
raise DuplicateDefinitionError, "
|
39
|
+
raise DuplicateDefinitionError, "#{@name} already registered: #{name}"
|
39
40
|
else
|
40
41
|
@items[name.to_sym] = item
|
41
42
|
end
|
@@ -95,7 +95,7 @@ end
|
|
95
95
|
World(FactoryGirlStepHelpers)
|
96
96
|
|
97
97
|
FactoryGirl.factories.each do |factory|
|
98
|
-
factory.
|
98
|
+
factory.compile
|
99
99
|
factory.human_names.each do |human_name|
|
100
100
|
Given /^the following (?:#{human_name}|#{human_name.pluralize}) exists?:$/i do |table|
|
101
101
|
table.hashes.each do |human_hash|
|
@@ -18,7 +18,7 @@ module FactoryGirl
|
|
18
18
|
|
19
19
|
def factory(name, options = {}, &block)
|
20
20
|
factory = Factory.new(name, options)
|
21
|
-
proxy = FactoryGirl::DefinitionProxy.new(factory)
|
21
|
+
proxy = FactoryGirl::DefinitionProxy.new(factory.definition)
|
22
22
|
proxy.instance_eval(&block) if block_given?
|
23
23
|
|
24
24
|
FactoryGirl.register_factory(factory)
|
@@ -43,10 +43,9 @@ module FactoryGirl
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def factory(name, options = {}, &block)
|
46
|
-
factory = FactoryGirl.factory_by_name(name)
|
47
|
-
proxy = FactoryGirl::DefinitionProxy.new(factory)
|
46
|
+
factory = FactoryGirl.factory_by_name(name)
|
47
|
+
proxy = FactoryGirl::DefinitionProxy.new(factory.definition.overridable)
|
48
48
|
proxy.instance_eval(&block)
|
49
|
-
factory.ensure_compiled
|
50
49
|
end
|
51
50
|
end
|
52
51
|
end
|
@@ -8,16 +8,17 @@ module FactoryGirl
|
|
8
8
|
# Arguments:
|
9
9
|
# * name: +Symbol+ or +String+
|
10
10
|
# The name of the factory that should be used.
|
11
|
-
# *
|
12
|
-
#
|
11
|
+
# * traits_and_overrides: +Array+
|
12
|
+
# [+*Array+] Traits to be applied
|
13
|
+
# [+Hash+] Attributes to overwrite for this set.
|
13
14
|
# * block:
|
14
15
|
# Yields the hash of attributes.
|
15
16
|
#
|
16
17
|
# Returns: +Hash+
|
17
18
|
# A set of attributes that can be used to build an instance of the class
|
18
19
|
# this factory generates.
|
19
|
-
def attributes_for(name,
|
20
|
-
|
20
|
+
def attributes_for(name, *traits_and_overrides, &block)
|
21
|
+
run_factory_girl_proxy(name, traits_and_overrides, Proxy::AttributesFor, &block)
|
21
22
|
end
|
22
23
|
|
23
24
|
# Generates and returns an instance from this factory. Attributes can be
|
@@ -26,16 +27,17 @@ module FactoryGirl
|
|
26
27
|
# Arguments:
|
27
28
|
# * name: +Symbol+ or +String+
|
28
29
|
# The name of the factory that should be used.
|
29
|
-
# *
|
30
|
-
#
|
30
|
+
# * traits_and_overrides: +Array+
|
31
|
+
# [+*Array+] Traits to be applied
|
32
|
+
# [+Hash+] Attributes to overwrite for this instance.
|
31
33
|
# * block:
|
32
34
|
# Yields the built instance.
|
33
35
|
#
|
34
36
|
# Returns: +Object+
|
35
37
|
# An instance of the class this factory generates, with generated attributes
|
36
38
|
# assigned.
|
37
|
-
def build(name,
|
38
|
-
|
39
|
+
def build(name, *traits_and_overrides, &block)
|
40
|
+
run_factory_girl_proxy(name, traits_and_overrides, Proxy::Build, &block)
|
39
41
|
end
|
40
42
|
|
41
43
|
# Generates, saves, and returns an instance from this factory. Attributes can
|
@@ -48,16 +50,17 @@ module FactoryGirl
|
|
48
50
|
# Arguments:
|
49
51
|
# * name: +Symbol+ or +String+
|
50
52
|
# The name of the factory that should be used.
|
51
|
-
# *
|
52
|
-
#
|
53
|
+
# * traits_and_overrides: +Array+
|
54
|
+
# [+*Array+] Traits to be applied
|
55
|
+
# [+Hash+] Attributes to overwrite for this instance.
|
53
56
|
# * block:
|
54
57
|
# Yields the created instance.
|
55
58
|
#
|
56
59
|
# Returns: +Object+
|
57
60
|
# A saved instance of the class this factory generates, with generated
|
58
61
|
# attributes assigned.
|
59
|
-
def create(name,
|
60
|
-
|
62
|
+
def create(name, *traits_and_overrides, &block)
|
63
|
+
run_factory_girl_proxy(name, traits_and_overrides, Proxy::Create, &block)
|
61
64
|
end
|
62
65
|
|
63
66
|
# Generates and returns an object with all attributes from this factory
|
@@ -67,15 +70,16 @@ module FactoryGirl
|
|
67
70
|
# Arguments:
|
68
71
|
# * name: +Symbol+ or +String+
|
69
72
|
# The name of the factory that should be used.
|
70
|
-
# *
|
71
|
-
#
|
73
|
+
# * traits_and_overrides: +Array+
|
74
|
+
# [+*Array+] Traits to be applied
|
75
|
+
# [+Hash+] Attributes to overwrite for this instance.
|
72
76
|
# * block
|
73
77
|
# Yields the stubbed object.
|
74
78
|
#
|
75
79
|
# Returns: +Object+
|
76
80
|
# An object with generated attributes stubbed out.
|
77
|
-
def build_stubbed(name,
|
78
|
-
|
81
|
+
def build_stubbed(name, *traits_and_overrides, &block)
|
82
|
+
run_factory_girl_proxy(name, traits_and_overrides, Proxy::Stub, &block)
|
79
83
|
end
|
80
84
|
|
81
85
|
# Builds and returns multiple instances from this factory as an array. Attributes can be
|
@@ -125,6 +129,24 @@ module FactoryGirl
|
|
125
129
|
def generate(name)
|
126
130
|
FactoryGirl.sequence_by_name(name).next
|
127
131
|
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def run_factory_girl_proxy(name, traits_and_overrides, proxy, &block)
|
136
|
+
overrides = if traits_and_overrides.last.respond_to?(:has_key?)
|
137
|
+
traits_and_overrides.pop
|
138
|
+
else
|
139
|
+
{}
|
140
|
+
end
|
141
|
+
|
142
|
+
factory = FactoryGirl.factory_by_name(name)
|
143
|
+
|
144
|
+
if traits_and_overrides.any?
|
145
|
+
factory = factory.with_traits(traits_and_overrides)
|
146
|
+
end
|
147
|
+
|
148
|
+
factory.run(proxy, overrides, &block)
|
149
|
+
end
|
128
150
|
end
|
129
151
|
end
|
130
152
|
end
|
data/lib/factory_girl/trait.rb
CHANGED
@@ -4,34 +4,26 @@ module FactoryGirl
|
|
4
4
|
|
5
5
|
def initialize(name, &block) #:nodoc:
|
6
6
|
@name = name
|
7
|
-
@
|
7
|
+
@block = block
|
8
|
+
@definition = Definition.new
|
8
9
|
|
9
|
-
proxy = FactoryGirl::DefinitionProxy.new(
|
10
|
-
proxy.instance_eval(
|
10
|
+
proxy = FactoryGirl::DefinitionProxy.new(@definition)
|
11
|
+
proxy.instance_eval(&@block) if block_given?
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
declaration
|
16
|
-
end
|
14
|
+
delegate :add_callback, :declare_attribute, :to_create, :define_trait,
|
15
|
+
:callbacks, :attributes, :to => :@definition
|
17
16
|
|
18
|
-
def
|
19
|
-
@
|
17
|
+
def names
|
18
|
+
[@name]
|
20
19
|
end
|
21
20
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
declaration.to_attributes.each do |attribute|
|
26
|
-
list.define_attribute(attribute)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
list.apply_attributes @attribute_list
|
30
|
-
end
|
21
|
+
def ==(other)
|
22
|
+
name == other.name &&
|
23
|
+
block == other.block
|
31
24
|
end
|
32
25
|
|
33
|
-
|
34
|
-
|
35
|
-
end
|
26
|
+
protected
|
27
|
+
attr_reader :block
|
36
28
|
end
|
37
29
|
end
|
data/lib/factory_girl/version.rb
CHANGED
@@ -39,7 +39,7 @@ describe "modifying factories" do
|
|
39
39
|
it "doesn't allow the factory to be subsequently defined" do
|
40
40
|
expect do
|
41
41
|
FactoryGirl.define { factory :user }
|
42
|
-
end.to raise_error(FactoryGirl::DuplicateDefinitionError)
|
42
|
+
end.to raise_error(FactoryGirl::DuplicateDefinitionError, "Factory already registered: user")
|
43
43
|
end
|
44
44
|
|
45
45
|
it "does allow the factory to be subsequently modified" do
|
@@ -165,6 +165,92 @@ describe "an instance generated by a factory with multiple traits" do
|
|
165
165
|
|
166
166
|
context "factory outside of scope" do
|
167
167
|
subject { FactoryGirl.create(:user_without_admin_scoping) }
|
168
|
-
it { expect { subject }.to raise_error(ArgumentError, "
|
168
|
+
it { expect { subject }.to raise_error(ArgumentError, "Trait not registered: admin_trait") }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "traits with callbacks" do
|
173
|
+
before do
|
174
|
+
define_model("User", :name => :string)
|
175
|
+
|
176
|
+
FactoryGirl.define do
|
177
|
+
factory :user do
|
178
|
+
name "John"
|
179
|
+
|
180
|
+
trait :great do
|
181
|
+
after_create {|user| user.name.upcase! }
|
182
|
+
end
|
183
|
+
|
184
|
+
factory :caps_user, :traits => [:great]
|
185
|
+
|
186
|
+
factory :caps_user_implicit_trait do
|
187
|
+
great
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "when the factory has a trait passed via arguments" do
|
194
|
+
subject { FactoryGirl.create(:caps_user) }
|
195
|
+
its(:name) { should == "JOHN" }
|
196
|
+
end
|
197
|
+
|
198
|
+
context "when the factory has an implicit trait" do
|
199
|
+
subject { FactoryGirl.create(:caps_user_implicit_trait) }
|
200
|
+
its(:name) { should == "JOHN" }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "traits added via proxy" do
|
205
|
+
before do
|
206
|
+
define_model("User", :name => :string, :admin => :boolean)
|
207
|
+
|
208
|
+
FactoryGirl.define do
|
209
|
+
factory :user do
|
210
|
+
name "John"
|
211
|
+
|
212
|
+
trait :admin do
|
213
|
+
admin true
|
214
|
+
end
|
215
|
+
|
216
|
+
trait :great do
|
217
|
+
after_create {|user| user.name.upcase! }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
context "adding traits in create" do
|
224
|
+
subject { FactoryGirl.create(:user, :admin, :great, :name => "Joe") }
|
225
|
+
|
226
|
+
its(:admin) { should be_true }
|
227
|
+
its(:name) { should == "JOE" }
|
228
|
+
|
229
|
+
it "doesn't modify the user factory" do
|
230
|
+
subject
|
231
|
+
FactoryGirl.create(:user).should_not be_admin
|
232
|
+
FactoryGirl.create(:user).name.should == "John"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "adding traits in build" do
|
237
|
+
subject { FactoryGirl.build(:user, :admin, :great, :name => "Joe") }
|
238
|
+
|
239
|
+
its(:admin) { should be_true }
|
240
|
+
its(:name) { should == "Joe" }
|
241
|
+
end
|
242
|
+
|
243
|
+
context "adding traits in attributes_for" do
|
244
|
+
subject { FactoryGirl.attributes_for(:user, :admin, :great) }
|
245
|
+
|
246
|
+
its([:admin]) { should be_true }
|
247
|
+
its([:name]) { should == "John" }
|
248
|
+
end
|
249
|
+
|
250
|
+
context "adding traits in build_stubbed" do
|
251
|
+
subject { FactoryGirl.build_stubbed(:user, :admin, :great, :name => "Jack") }
|
252
|
+
|
253
|
+
its(:admin) { should be_true }
|
254
|
+
its(:name) { should == "Jack" }
|
169
255
|
end
|
170
256
|
end
|