thoughtbot-factory_girl 1.2.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTION_GUIDELINES.rdoc +4 -5
- data/README.rdoc +6 -6
- data/Rakefile +11 -14
- data/lib/factory_girl/attribute.rb +3 -2
- data/lib/factory_girl/attribute/dynamic.rb +5 -2
- data/lib/factory_girl/proxy/stub.rb +33 -12
- data/lib/factory_girl/sequence.rb +3 -0
- data/spec/factory_girl/aliases_spec.rb +29 -0
- data/spec/factory_girl/attribute/association_spec.rb +25 -0
- data/spec/factory_girl/attribute/dynamic_spec.rb +49 -0
- data/spec/factory_girl/attribute/static_spec.rb +29 -0
- data/spec/factory_girl/attribute_spec.rb +30 -0
- data/spec/factory_girl/factory_spec.rb +490 -0
- data/spec/factory_girl/proxy/attributes_for_spec.rb +52 -0
- data/spec/factory_girl/proxy/build_spec.rb +73 -0
- data/spec/factory_girl/proxy/create_spec.rb +83 -0
- data/spec/factory_girl/proxy/stub_spec.rb +69 -0
- data/spec/factory_girl/proxy_spec.rb +28 -0
- data/spec/factory_girl/sequence_spec.rb +66 -0
- data/spec/factory_girl/syntax/blueprint_spec.rb +34 -0
- data/spec/factory_girl/syntax/generate_spec.rb +57 -0
- data/spec/factory_girl/syntax/make_spec.rb +35 -0
- data/spec/factory_girl/syntax/sham_spec.rb +35 -0
- data/spec/integration_spec.rb +265 -0
- data/{test → spec}/models.rb +0 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +12 -5
- metadata +42 -43
- data/test/aliases_test.rb +0 -29
- data/test/association_attribute_test.rb +0 -31
- data/test/attribute_test.rb +0 -32
- data/test/attributes_for_strategy_test.rb +0 -55
- data/test/build_strategy_test.rb +0 -79
- data/test/create_strategy_test.rb +0 -90
- data/test/dynamic_attribute_test.rb +0 -41
- data/test/factory_test.rb +0 -513
- data/test/integration_test.rb +0 -235
- data/test/sequence_test.rb +0 -76
- data/test/static_attribute_test.rb +0 -33
- data/test/strategy_test.rb +0 -33
- data/test/stub_strategy_test.rb +0 -61
- data/test/syntax/blueprint_test.rb +0 -39
- data/test/syntax/generate_test.rb +0 -63
- data/test/syntax/make_test.rb +0 -39
- data/test/syntax/sham_test.rb +0 -40
@@ -1,10 +1,9 @@
|
|
1
|
-
We're using GitHub[http://github.com/thoughtbot/factory_girl/tree/master]
|
1
|
+
We're using GitHub[http://github.com/thoughtbot/factory_girl/tree/master], and we've been getting any combination of github pull requests, patches, emails, etc. We need to normalize this workflow to make sure we don't miss any fixes.
|
2
2
|
|
3
3
|
* Make sure you're accessing the source from the {official repository}[http://github.com/thoughtbot/factory_girl/tree/master].
|
4
|
-
* We
|
5
|
-
* If you're using git, please make a branch for each separate contribution. We can cherry pick your commits, but pulling from a branch is easier.
|
4
|
+
* Please make a branch for each separate contribution. We can cherry pick your commits, but pulling from a branch is easier.
|
6
5
|
* If you're submitting patches, please cut each fix or feature into a separate patch.
|
7
|
-
* There should be
|
8
|
-
* Please <b>don't send pull requests</b> Just update the
|
6
|
+
* There should be an issue[http://github.com/thoughtbot/factory_girl/issues] for any submission. If you've found a bug and want to fix it, open a new ticket at the same time.
|
7
|
+
* Please <b>don't send pull requests</b> Just update the issue with the url for your fix when it's ready. The github pull requests pretty much get dropped on the floor until someone with commit rights notices them in the mailbox.
|
9
8
|
* Contributions without tests won't be accepted.
|
10
9
|
* Please don't submit patches or branches that update the Gem version.
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= factory_girl
|
2
2
|
|
3
|
-
factory_girl is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory
|
3
|
+
factory_girl is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance.
|
4
4
|
|
5
5
|
== Download
|
6
6
|
|
@@ -18,7 +18,7 @@ in your environment.rb if you want to use Rails 2.1+'s dependency manager:
|
|
18
18
|
|
19
19
|
== Defining factories
|
20
20
|
|
21
|
-
Each factory has a name and a set of attributes. The name is used to guess the class of the object by default, but it's possible to
|
21
|
+
Each factory has a name and a set of attributes. The name is used to guess the class of the object by default, but it's possible to explicitly specify it:
|
22
22
|
|
23
23
|
# This will guess the User class
|
24
24
|
Factory.define :user do |u|
|
@@ -41,7 +41,7 @@ Each factory has a name and a set of attributes. The name is used to guess the c
|
|
41
41
|
u.admin true
|
42
42
|
end
|
43
43
|
|
44
|
-
It is highly recommended that you have one factory for each class that provides the simplest set of attributes necessary to create an instance of that class. If you're creating ActiveRecord objects, that means that you should only provide attributes that are required through validations and that do not have defaults. Other factories can be created through
|
44
|
+
It is highly recommended that you have one factory for each class that provides the simplest set of attributes necessary to create an instance of that class. If you're creating ActiveRecord objects, that means that you should only provide attributes that are required through validations and that do not have defaults. Other factories can be created through inheritance to cover common scenarios for each class.
|
45
45
|
|
46
46
|
Factories can either be defined anywhere, but will automatically be loaded if they are defined in files at the following locations:
|
47
47
|
|
@@ -148,7 +148,7 @@ be left out.
|
|
148
148
|
|
149
149
|
== Inheritance
|
150
150
|
|
151
|
-
You can easily create multiple factories for the same class without repeating common attributes by using
|
151
|
+
You can easily create multiple factories for the same class without repeating common attributes by using inheritance:
|
152
152
|
|
153
153
|
Factory.define :post do |p|
|
154
154
|
# the 'title' attribute is required for all posts
|
@@ -199,11 +199,11 @@ Users' tastes for syntax vary dramatically, but most users are looking for a com
|
|
199
199
|
|
200
200
|
Our blog: http://giantrobots.thoughtbot.com
|
201
201
|
|
202
|
-
factory_girl rdoc: http://
|
202
|
+
factory_girl rdoc: http://rdoc.info/projects/thoughtbot/factory_girl
|
203
203
|
|
204
204
|
Mailing list: http://groups.google.com/group/factory_girl
|
205
205
|
|
206
|
-
factory_girl
|
206
|
+
factory_girl issues: http://github.com/thoughtbot/factory_girl/issues
|
207
207
|
|
208
208
|
== Contributing
|
209
209
|
|
data/Rakefile
CHANGED
@@ -1,26 +1,22 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
-
require 'rake/testtask'
|
4
3
|
require 'rake/rdoctask'
|
5
4
|
require 'rake/gempackagetask'
|
6
5
|
require 'rcov/rcovtask'
|
7
6
|
require 'date'
|
8
7
|
|
9
|
-
|
10
|
-
task :default => :test
|
8
|
+
require 'spec/rake/spectask'
|
11
9
|
|
12
|
-
desc '
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
t.
|
17
|
-
t.verbose = true
|
10
|
+
desc 'Default: run the specs.'
|
11
|
+
task :default => :spec
|
12
|
+
|
13
|
+
Spec::Rake::SpecTask.new do |t|
|
14
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
18
15
|
end
|
19
16
|
|
20
17
|
desc 'Performs code coverage on the factory_girl plugin.'
|
21
18
|
Rcov::RcovTask.new do |t|
|
22
|
-
t.
|
23
|
-
t.test_files = FileList['test/*_test.rb']
|
19
|
+
t.test_files = FileList['spec/*_spec.rb']
|
24
20
|
t.verbose = true
|
25
21
|
end
|
26
22
|
|
@@ -41,16 +37,16 @@ end
|
|
41
37
|
|
42
38
|
spec = Gem::Specification.new do |s|
|
43
39
|
s.name = %q{factory_girl}
|
44
|
-
s.version = "1.2.
|
40
|
+
s.version = "1.2.2"
|
45
41
|
s.summary = %q{factory_girl provides a framework and DSL for defining and
|
46
42
|
using model instance factories.}
|
47
43
|
s.description = %q{factory_girl provides a framework and DSL for defining and
|
48
44
|
using factories - less error-prone, more explicit, and
|
49
45
|
all-around easier to work with than fixtures.}
|
50
46
|
|
51
|
-
s.files = FileList['[A-Z]*', 'lib/**/*.rb', '
|
47
|
+
s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'spec/**/*.rb']
|
52
48
|
s.require_path = 'lib'
|
53
|
-
s.test_files = Dir[*['
|
49
|
+
s.test_files = Dir[*['spec/**/*_spec.rb']]
|
54
50
|
|
55
51
|
s.has_rdoc = true
|
56
52
|
s.extra_rdoc_files = ["README.rdoc"]
|
@@ -58,6 +54,7 @@ spec = Gem::Specification.new do |s|
|
|
58
54
|
|
59
55
|
s.authors = ["Joe Ferris"]
|
60
56
|
s.email = %q{jferris@thoughtbot.com}
|
57
|
+
s.homepage = "http://thoughtbot.com/projects/factory_girl"
|
61
58
|
|
62
59
|
s.platform = Gem::Platform::RUBY
|
63
60
|
end
|
@@ -15,9 +15,10 @@ class Factory
|
|
15
15
|
@name = name.to_sym
|
16
16
|
|
17
17
|
if @name.to_s =~ /=$/
|
18
|
+
attribute_name = $`
|
18
19
|
raise AttributeDefinitionError,
|
19
|
-
"factory_girl uses 'f.#{
|
20
|
-
"rather than 'f.#{
|
20
|
+
"factory_girl uses 'f.#{attribute_name} value' syntax " +
|
21
|
+
"rather than 'f.#{attribute_name} = value'"
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
@@ -2,14 +2,17 @@ class Factory
|
|
2
2
|
class Attribute #:nodoc:
|
3
3
|
|
4
4
|
class Dynamic < Attribute #:nodoc:
|
5
|
-
|
6
5
|
def initialize(name, block)
|
7
6
|
super(name)
|
8
7
|
@block = block
|
9
8
|
end
|
10
9
|
|
11
10
|
def add_to(proxy)
|
12
|
-
|
11
|
+
value = @block.arity.zero? ? @block.call : @block.call(proxy)
|
12
|
+
if Factory::Sequence === value
|
13
|
+
raise SequenceAbuseError
|
14
|
+
end
|
15
|
+
proxy.set(name, value)
|
13
16
|
end
|
14
17
|
end
|
15
18
|
|
@@ -1,27 +1,48 @@
|
|
1
1
|
class Factory
|
2
2
|
class Proxy
|
3
3
|
class Stub < Proxy #:nodoc:
|
4
|
+
@@next_id = 1000
|
5
|
+
|
4
6
|
def initialize(klass)
|
5
|
-
@
|
7
|
+
@stub = klass.new
|
8
|
+
@stub.id = next_id
|
9
|
+
@stub.instance_eval do
|
10
|
+
def new_record?
|
11
|
+
id.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection
|
15
|
+
raise "stubbed models are not allowed to access the database"
|
16
|
+
end
|
17
|
+
|
18
|
+
def reload
|
19
|
+
raise "stubbed models are not allowed to access the database"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_id
|
25
|
+
@@next_id += 1
|
6
26
|
end
|
7
|
-
|
27
|
+
|
8
28
|
def get(attribute)
|
9
|
-
@
|
29
|
+
@stub.send(attribute)
|
10
30
|
end
|
11
|
-
|
31
|
+
|
12
32
|
def set(attribute, value)
|
13
|
-
|
14
|
-
class << @mock; self end.send(:attr_accessor, attribute)
|
15
|
-
end
|
16
|
-
@mock.send("#{attribute}=", value)
|
33
|
+
@stub.send(:"#{attribute}=", value)
|
17
34
|
end
|
18
|
-
|
35
|
+
|
19
36
|
def associate(name, factory, attributes)
|
20
|
-
set(name,
|
37
|
+
set(name, Factory.stub(factory, attributes))
|
38
|
+
end
|
39
|
+
|
40
|
+
def association(factory, overrides = {})
|
41
|
+
Factory.stub(factory, overrides)
|
21
42
|
end
|
22
|
-
|
43
|
+
|
23
44
|
def result
|
24
|
-
@
|
45
|
+
@stub
|
25
46
|
end
|
26
47
|
end
|
27
48
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Factory, "aliases" do
|
4
|
+
|
5
|
+
it "should include an attribute as an alias for itself by default" do
|
6
|
+
Factory.aliases_for(:test).should include(:test)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should include the root of a foreign key as an alias by default" do
|
10
|
+
Factory.aliases_for(:test_id).should include(:test)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should include an attribute's foreign key as an alias by default" do
|
14
|
+
Factory.aliases_for(:test).should include(:test_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "after adding an alias" do
|
18
|
+
|
19
|
+
before do
|
20
|
+
Factory.alias(/(.*)_suffix/, '\1')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return the alias in the aliases list" do
|
24
|
+
Factory.aliases_for(:test_suffix).should include(:test)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Factory::Attribute::Association do
|
4
|
+
before do
|
5
|
+
@name = :author
|
6
|
+
@factory = :user
|
7
|
+
@overrides = { :first_name => 'John' }
|
8
|
+
@attr = Factory::Attribute::Association.new(@name, @factory, @overrides)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have a name" do
|
12
|
+
@attr.name.should == @name
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should tell the proxy to associate when being added to a proxy" do
|
16
|
+
proxy = "proxy"
|
17
|
+
stub(proxy).associate
|
18
|
+
@attr.add_to(proxy)
|
19
|
+
proxy.should have_received.associate(@name, @factory, @overrides)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should convert names to symbols" do
|
23
|
+
Factory::Attribute::Association.new('name', :user, {}).name.should == :name
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Factory::Attribute::Dynamic do
|
4
|
+
before do
|
5
|
+
@name = :first_name
|
6
|
+
@block = lambda { 'value' }
|
7
|
+
@attr = Factory::Attribute::Dynamic.new(@name, @block)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a name" do
|
11
|
+
@attr.name.should == @name
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should call the block to set a value" do
|
15
|
+
@proxy = "proxy"
|
16
|
+
stub(@proxy).set
|
17
|
+
@attr.add_to(@proxy)
|
18
|
+
@proxy.should have_received.set(@name, 'value')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should yield the proxy to the block when adding its value to a proxy" do
|
22
|
+
@block = lambda {|a| a }
|
23
|
+
@attr = Factory::Attribute::Dynamic.new(:user, @block)
|
24
|
+
@proxy = "proxy"
|
25
|
+
stub(@proxy).set
|
26
|
+
@attr.add_to(@proxy)
|
27
|
+
@proxy.should have_received.set(:user, @proxy)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should raise an error when defining an attribute writer" do
|
31
|
+
lambda {
|
32
|
+
Factory::Attribute::Dynamic.new('test=', nil)
|
33
|
+
}.should raise_error(Factory::AttributeDefinitionError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise an error when returning a sequence" do
|
37
|
+
stub(Factory).sequence { Factory::Sequence.new }
|
38
|
+
block = lambda { Factory.sequence(:email) }
|
39
|
+
attr = Factory::Attribute::Dynamic.new(:email, block)
|
40
|
+
proxy = stub!.set.subject
|
41
|
+
lambda {
|
42
|
+
attr.add_to(proxy)
|
43
|
+
}.should raise_error(Factory::SequenceAbuseError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should convert names to symbols" do
|
47
|
+
Factory::Attribute::Dynamic.new('name', nil).name.should == :name
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Factory::Attribute::Static do
|
4
|
+
before do
|
5
|
+
@name = :first_name
|
6
|
+
@value = 'John'
|
7
|
+
@attr = Factory::Attribute::Static.new(@name, @value)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a name" do
|
11
|
+
@attr.name.should == @name
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set its static value on a proxy" do
|
15
|
+
@proxy = "proxy"
|
16
|
+
mock(@proxy).set(@name, @value)
|
17
|
+
@attr.add_to(@proxy)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should raise an error when defining an attribute writer" do
|
21
|
+
lambda {
|
22
|
+
Factory::Attribute::Static.new('test=', nil)
|
23
|
+
}.should raise_error(Factory::AttributeDefinitionError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should convert names to symbols" do
|
27
|
+
Factory::Attribute::Static.new('name', nil).name.should == :name
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Factory::Attribute do
|
4
|
+
before do
|
5
|
+
@name = :user
|
6
|
+
@attr = Factory::Attribute.new(@name)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have a name" do
|
10
|
+
@attr.name.should == @name
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should do nothing when being added to a proxy" do
|
14
|
+
@proxy = "proxy"
|
15
|
+
stub(@proxy).set
|
16
|
+
@attr.add_to(@proxy)
|
17
|
+
@proxy.should have_received.set.never
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should raise an error when defining an attribute writer" do
|
21
|
+
error_message = %{factory_girl uses 'f.test value' syntax rather than 'f.test = value'}
|
22
|
+
lambda {
|
23
|
+
Factory::Attribute.new('test=')
|
24
|
+
}.should raise_error(Factory::AttributeDefinitionError, error_message)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should convert names to symbols" do
|
28
|
+
Factory::Attribute.new('name').name.should == :name
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,490 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Factory do
|
4
|
+
describe "defining a factory" do
|
5
|
+
before do
|
6
|
+
@name = :user
|
7
|
+
@factory = "factory"
|
8
|
+
stub(@factory).factory_name { @name }
|
9
|
+
@options = { :class => 'magic' }
|
10
|
+
stub(Factory).new { @factory }
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should create a new factory using the specified name and options" do
|
14
|
+
mock(Factory).new(@name, @options) { @factory }
|
15
|
+
Factory.define(@name, @options) {|f| }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should pass the factory do the block" do
|
19
|
+
yielded = nil
|
20
|
+
Factory.define(@name) do |y|
|
21
|
+
yielded = y
|
22
|
+
end
|
23
|
+
yielded.should == @factory
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should add the factory to the list of factories" do
|
27
|
+
Factory.define(@name) {|f| }
|
28
|
+
@factory.should == Factory.factories[@name]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "a factory" do
|
33
|
+
before do
|
34
|
+
@name = :user
|
35
|
+
@class = User
|
36
|
+
@factory = Factory.new(@name)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have a factory name" do
|
40
|
+
@factory.factory_name.should == @name
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should have a build class" do
|
44
|
+
@factory.build_class.should == @class
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have a default strategy" do
|
48
|
+
@factory.default_strategy.should == :create
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not allow the same attribute to be added twice" do
|
52
|
+
lambda {
|
53
|
+
2.times { @factory.add_attribute :first_name }
|
54
|
+
}.should raise_error(Factory::AttributeDefinitionError)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should add a static attribute when an attribute is defined with a value" do
|
58
|
+
attribute = 'attribute'
|
59
|
+
stub(attribute).name { :name }
|
60
|
+
mock(Factory::Attribute::Static).new(:name, 'value') { attribute }
|
61
|
+
@factory.add_attribute(:name, 'value')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should add a dynamic attribute when an attribute is defined with a block" do
|
65
|
+
attribute = 'attribute'
|
66
|
+
stub(attribute).name { :name }
|
67
|
+
block = lambda {}
|
68
|
+
mock(Factory::Attribute::Dynamic).new(:name, block) { attribute }
|
69
|
+
@factory.add_attribute(:name, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should raise for an attribute with a value and a block" do
|
73
|
+
lambda {
|
74
|
+
@factory.add_attribute(:name, 'value') {}
|
75
|
+
}.should raise_error(Factory::AttributeDefinitionError)
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "adding an attribute using a in-line sequence" do
|
79
|
+
it "should create the sequence" do
|
80
|
+
mock(Factory::Sequence).new
|
81
|
+
@factory.sequence(:name) {}
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should add a dynamic attribute" do
|
85
|
+
attribute = 'attribute'
|
86
|
+
stub(attribute).name { :name }
|
87
|
+
mock(Factory::Attribute::Dynamic).new(:name, is_a(Proc)) { attribute }
|
88
|
+
@factory.sequence(:name) {}
|
89
|
+
@factory.attributes.should include(attribute)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "after adding an attribute" do
|
94
|
+
before do
|
95
|
+
@attribute = "attribute"
|
96
|
+
@proxy = "proxy"
|
97
|
+
|
98
|
+
stub(@attribute).name { :name }
|
99
|
+
stub(@attribute).add_to
|
100
|
+
stub(@proxy).set
|
101
|
+
stub(@proxy).result { 'result' }
|
102
|
+
stub(Factory::Attribute::Static).new { @attribute }
|
103
|
+
stub(Factory::Proxy::Build).new { @proxy }
|
104
|
+
|
105
|
+
@factory.add_attribute(:name, 'value')
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should create the right proxy using the build class when running" do
|
109
|
+
mock(Factory::Proxy::Build).new(@factory.build_class) { @proxy }
|
110
|
+
@factory.run(Factory::Proxy::Build, {})
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should add the attribute to the proxy when running" do
|
114
|
+
mock(@attribute).add_to(@proxy)
|
115
|
+
@factory.run(Factory::Proxy::Build, {})
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should return the result from the proxy when running" do
|
119
|
+
mock(@proxy).result() { 'result' }
|
120
|
+
@factory.run(Factory::Proxy::Build, {}).should == 'result'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should add an association without a factory name or overrides" do
|
125
|
+
factory = Factory.new(:post)
|
126
|
+
name = :user
|
127
|
+
attr = 'attribute'
|
128
|
+
mock(Factory::Attribute::Association).new(name, name, {}) { attr }
|
129
|
+
factory.association(name)
|
130
|
+
factory.attributes.should include(attr)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should add an association with overrides" do
|
134
|
+
factory = Factory.new(:post)
|
135
|
+
name = :user
|
136
|
+
attr = 'attribute'
|
137
|
+
overrides = { :first_name => 'Ben' }
|
138
|
+
mock(Factory::Attribute::Association).new(name, name, overrides) { attr }
|
139
|
+
factory.association(name, overrides)
|
140
|
+
factory.attributes.should include(attr)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should add an association with a factory name" do
|
144
|
+
factory = Factory.new(:post)
|
145
|
+
attr = 'attribute'
|
146
|
+
mock(Factory::Attribute::Association).new(:author, :user, {}) { attr }
|
147
|
+
factory.association(:author, :factory => :user)
|
148
|
+
factory.attributes.should include(attr)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should add an association with a factory name and overrides" do
|
152
|
+
factory = Factory.new(:post)
|
153
|
+
attr = 'attribute'
|
154
|
+
mock(Factory::Attribute::Association).new(:author, :user, :first_name => 'Ben') { attr }
|
155
|
+
factory.association(:author, :factory => :user, :first_name => 'Ben')
|
156
|
+
factory.attributes.should include(attr)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should raise for a self referencing association" do
|
160
|
+
factory = Factory.new(:post)
|
161
|
+
lambda {
|
162
|
+
factory.association(:parent, :factory => :post)
|
163
|
+
}.should raise_error(Factory::AssociationDefinitionError)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should add an attribute using the method name when passed an undefined method" do
|
167
|
+
attribute = 'attribute'
|
168
|
+
stub(attribute).name { :name }
|
169
|
+
block = lambda {}
|
170
|
+
mock(Factory::Attribute::Static).new(:name, 'value') { attribute }
|
171
|
+
@factory.send(:name, 'value')
|
172
|
+
@factory.attributes.should include(attribute)
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "when overriding generated attributes with a hash" do
|
176
|
+
before do
|
177
|
+
@attr = :name
|
178
|
+
@value = 'The price is right!'
|
179
|
+
@hash = { @attr => @value }
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should return the overridden value in the generated attributes" do
|
183
|
+
@factory.add_attribute(@attr, 'The price is wrong, Bob!')
|
184
|
+
result = @factory.run(Factory::Proxy::AttributesFor, @hash)
|
185
|
+
result[@attr].should == @value
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should not call a lazy attribute block for an overridden attribute" do
|
189
|
+
@factory.add_attribute(@attr) { flunk }
|
190
|
+
result = @factory.run(Factory::Proxy::AttributesFor, @hash)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should override a symbol parameter with a string parameter" do
|
194
|
+
@factory.add_attribute(@attr, 'The price is wrong, Bob!')
|
195
|
+
@hash = { @attr.to_s => @value }
|
196
|
+
result = @factory.run(Factory::Proxy::AttributesFor, @hash)
|
197
|
+
result[@attr].should == @value
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "overriding an attribute with an alias" do
|
202
|
+
before do
|
203
|
+
@factory.add_attribute(:test, 'original')
|
204
|
+
Factory.alias(/(.*)_alias/, '\1')
|
205
|
+
@result = @factory.run(Factory::Proxy::AttributesFor,
|
206
|
+
:test_alias => 'new')
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should use the passed in value for the alias" do
|
210
|
+
@result[:test_alias].should == 'new'
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should discard the predefined value for the attribute" do
|
214
|
+
@result[:test].should be_nil
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should guess the build class from the factory name" do
|
219
|
+
@factory.build_class.should == User
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "when defined with a custom class" do
|
223
|
+
before do
|
224
|
+
@class = User
|
225
|
+
@factory = Factory.new(:author, :class => @class)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should use the specified class as the build class" do
|
229
|
+
@factory.build_class.should == @class
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "when defined with a class instead of a name" do
|
234
|
+
before do
|
235
|
+
@class = ArgumentError
|
236
|
+
@name = :argument_error
|
237
|
+
@factory = Factory.new(@class)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should guess the name from the class" do
|
241
|
+
@factory.factory_name.should == @name
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should use the class as the build class" do
|
245
|
+
@factory.build_class.should == @class
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
describe "when defined with a custom class name" do
|
250
|
+
before do
|
251
|
+
@class = ArgumentError
|
252
|
+
@factory = Factory.new(:author, :class => :argument_error)
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should use the specified class as the build class" do
|
256
|
+
@factory.build_class.should == @class
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "a factory with a name ending in s" do
|
262
|
+
before do
|
263
|
+
@name = :business
|
264
|
+
@class = Business
|
265
|
+
@factory = Factory.new(@name)
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should have a factory name" do
|
269
|
+
@factory.factory_name.should == @name
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should have a build class" do
|
273
|
+
@factory.build_class.should == @class
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
describe "a factory with a string for a name" do
|
278
|
+
before do
|
279
|
+
@name = :user
|
280
|
+
@factory = Factory.new(@name.to_s) {}
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should convert the string to a symbol" do
|
284
|
+
@factory.factory_name.should == @name
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "a factory defined with a string name" do
|
289
|
+
before do
|
290
|
+
Factory.factories = {}
|
291
|
+
@name = :user
|
292
|
+
@factory = Factory.define(@name.to_s) {}
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should store the factory using a symbol" do
|
296
|
+
Factory.factories[@name].should == @factory
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe "after defining a factory" do
|
301
|
+
before do
|
302
|
+
@name = :user
|
303
|
+
@factory = "factory"
|
304
|
+
|
305
|
+
Factory.factories[@name] = @factory
|
306
|
+
end
|
307
|
+
|
308
|
+
after { Factory.factories.clear }
|
309
|
+
|
310
|
+
it "should use Proxy::AttributesFor for Factory.attributes_for" do
|
311
|
+
mock(@factory).run(Factory::Proxy::AttributesFor, :attr => 'value') { 'result' }
|
312
|
+
Factory.attributes_for(@name, :attr => 'value').should == 'result'
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should use Proxy::Build for Factory.build" do
|
316
|
+
mock(@factory).run(Factory::Proxy::Build, :attr => 'value') { 'result' }
|
317
|
+
Factory.build(@name, :attr => 'value').should == 'result'
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should use Proxy::Create for Factory.create" do
|
321
|
+
mock(@factory).run(Factory::Proxy::Create, :attr => 'value') { 'result' }
|
322
|
+
Factory.create(@name, :attr => 'value').should == 'result'
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should use Proxy::Stub for Factory.stub" do
|
326
|
+
mock(@factory).run(Factory::Proxy::Stub, :attr => 'value') { 'result' }
|
327
|
+
Factory.stub(@name, :attr => 'value').should == 'result'
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should use default strategy option as Factory.default_strategy" do
|
331
|
+
stub(@factory).default_strategy { :create }
|
332
|
+
mock(@factory).run(Factory::Proxy::Create, :attr => 'value') { 'result' }
|
333
|
+
Factory.default_strategy(@name, :attr => 'value').should == 'result'
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should use the default strategy for the global Factory method" do
|
337
|
+
stub(@factory).default_strategy { :create }
|
338
|
+
mock(@factory).run(Factory::Proxy::Create, :attr => 'value') { 'result' }
|
339
|
+
Factory(@name, :attr => 'value').should == 'result'
|
340
|
+
end
|
341
|
+
|
342
|
+
[:build, :create, :attributes_for, :stub].each do |method|
|
343
|
+
it "should raise an ArgumentError on #{method} with a nonexistant factory" do
|
344
|
+
lambda { Factory.send(method, :bogus) }.should raise_error(ArgumentError)
|
345
|
+
end
|
346
|
+
|
347
|
+
it "should recognize either 'name' or :name for Factory.#{method}" do
|
348
|
+
stub(@factory).run
|
349
|
+
lambda { Factory.send(method, @name.to_s) }.should_not raise_error
|
350
|
+
lambda { Factory.send(method, @name.to_sym) }.should_not raise_error
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe 'defining a factory with a parent parameter' do
|
356
|
+
before do
|
357
|
+
@parent = Factory.define :object do |f|
|
358
|
+
f.name 'Name'
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should raise an ArgumentError when trying to use a non-existent factory as parent" do
|
363
|
+
lambda {
|
364
|
+
Factory.define(:child, :parent => :nonexsitent) {}
|
365
|
+
}.should raise_error(ArgumentError)
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should create a new factory using the class of the parent" do
|
369
|
+
child = Factory.define(:child, :parent => :object) {}
|
370
|
+
child.build_class.should == @parent.build_class
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should create a new factory while overriding the parent class" do
|
374
|
+
class Other; end
|
375
|
+
|
376
|
+
child = Factory.define(:child, :parent => :object, :class => Other) {}
|
377
|
+
child.build_class.should == Other
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should create a new factory with attributes of the parent" do
|
381
|
+
child = Factory.define(:child, :parent => :object) {}
|
382
|
+
child.attributes.size.should == 1
|
383
|
+
child.attributes.first.name.should == :name
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should allow to define additional attributes" do
|
387
|
+
child = Factory.define(:child, :parent => :object) do |f|
|
388
|
+
f.email 'person@somebody.com'
|
389
|
+
end
|
390
|
+
child.attributes.size.should == 2
|
391
|
+
end
|
392
|
+
|
393
|
+
it "should allow to override parent attributes" do
|
394
|
+
child = Factory.define(:child, :parent => :object) do |f|
|
395
|
+
f.name { 'Child Name' }
|
396
|
+
end
|
397
|
+
child.attributes.size.should == 1
|
398
|
+
child.attributes.first.should be_kind_of(Factory::Attribute::Dynamic)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
describe 'defining a factory with a default strategy parameter' do
|
403
|
+
it "should raise an ArgumentError when trying to use a non-existent factory" do
|
404
|
+
lambda {
|
405
|
+
Factory.define(:object, :default_strategy => :nonexistent) {}
|
406
|
+
}.should raise_error(ArgumentError)
|
407
|
+
end
|
408
|
+
|
409
|
+
it "should create a new factory with a specified default strategy" do
|
410
|
+
factory = Factory.define(:object, :default_strategy => :stub) {}
|
411
|
+
factory.default_strategy.should == :stub
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
def self.in_directory_with_files(*files)
|
416
|
+
before do
|
417
|
+
@pwd = Dir.pwd
|
418
|
+
@tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
|
419
|
+
FileUtils.mkdir_p @tmp_dir
|
420
|
+
Dir.chdir(@tmp_dir)
|
421
|
+
|
422
|
+
files.each do |file|
|
423
|
+
FileUtils.mkdir_p File.dirname(file)
|
424
|
+
FileUtils.touch file
|
425
|
+
stub(Factory).require(file)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
after do
|
430
|
+
Dir.chdir(@pwd)
|
431
|
+
FileUtils.rm_rf(@tmp_dir)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
def require_definitions_from(file)
|
436
|
+
simple_matcher do |given, matcher|
|
437
|
+
has_received = have_received.require(file)
|
438
|
+
result = has_received.matches?(given)
|
439
|
+
matcher.description = "require definitions from #{file}"
|
440
|
+
matcher.failure_message = has_received.failure_message
|
441
|
+
result
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
share_examples_for "finds definitions" do
|
446
|
+
before do
|
447
|
+
stub(Factory).require
|
448
|
+
Factory.find_definitions
|
449
|
+
end
|
450
|
+
subject { Factory }
|
451
|
+
end
|
452
|
+
|
453
|
+
describe "with factories.rb" do
|
454
|
+
in_directory_with_files 'factories.rb'
|
455
|
+
it_should_behave_like "finds definitions"
|
456
|
+
it { should require_definitions_from('factories.rb') }
|
457
|
+
end
|
458
|
+
|
459
|
+
%w(spec test).each do |dir|
|
460
|
+
describe "with a factories file under #{dir}" do
|
461
|
+
in_directory_with_files File.join(dir, 'factories.rb')
|
462
|
+
it_should_behave_like "finds definitions"
|
463
|
+
it { should require_definitions_from("#{dir}/factories.rb") }
|
464
|
+
end
|
465
|
+
|
466
|
+
describe "with a factories file under #{dir}/factories" do
|
467
|
+
in_directory_with_files File.join(dir, 'factories', 'post_factory.rb')
|
468
|
+
it_should_behave_like "finds definitions"
|
469
|
+
it { should require_definitions_from("#{dir}/factories/post_factory.rb") }
|
470
|
+
end
|
471
|
+
|
472
|
+
describe "with several factories files under #{dir}/factories" do
|
473
|
+
in_directory_with_files File.join(dir, 'factories', 'post_factory.rb'),
|
474
|
+
File.join(dir, 'factories', 'person_factory.rb')
|
475
|
+
it_should_behave_like "finds definitions"
|
476
|
+
it { should require_definitions_from("#{dir}/factories/post_factory.rb") }
|
477
|
+
it { should require_definitions_from("#{dir}/factories/person_factory.rb") }
|
478
|
+
end
|
479
|
+
|
480
|
+
describe "with nested and unnested factories files under #{dir}" do
|
481
|
+
in_directory_with_files File.join(dir, 'factories.rb'),
|
482
|
+
File.join(dir, 'factories', 'post_factory.rb'),
|
483
|
+
File.join(dir, 'factories', 'person_factory.rb')
|
484
|
+
it_should_behave_like "finds definitions"
|
485
|
+
it { should require_definitions_from("#{dir}/factories.rb") }
|
486
|
+
it { should require_definitions_from("#{dir}/factories/post_factory.rb") }
|
487
|
+
it { should require_definitions_from("#{dir}/factories/person_factory.rb") }
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|