factory_boy 1.0.1
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/README.rdoc +110 -0
- data/lib/factory_boy.rb +1 -0
- data/lib/plant.rb +90 -0
- data/lib/setup.rb +32 -0
- data/lib/stubber.rb +36 -0
- data/test/help_test.rb +9 -0
- data/test/models/adress.rb +12 -0
- data/test/models/customer.rb +7 -0
- data/test/models/profile.rb +8 -0
- data/test/models/user.rb +8 -0
- data/test/plants.rb +23 -0
- data/test/test_plant.rb +110 -0
- metadata +84 -0
data/README.rdoc
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
== Overview
|
2
|
+
Factory_boy aims to avoid slow unit tests due to usage of create/find fixtures in database, with factory_girl for example.
|
3
|
+
Factory_boy can be used as factory_girl except that factories are not created in database.
|
4
|
+
ActiveRecord::Base find method is stubbed to return fixtures (plants) you have instanciate.
|
5
|
+
Differenciate find :all, :first, :last, but doesn't do the work of find with sql conditions.
|
6
|
+
Anyway we don't think it's important for unit test, if some find calls with sql conditions, :include ... etc have to be
|
7
|
+
tested, report it in integration tests is a better idea.
|
8
|
+
|
9
|
+
See some examples below.
|
10
|
+
You can see also unit tests / code for deeper comprehension.
|
11
|
+
|
12
|
+
== Basic Usage
|
13
|
+
|
14
|
+
Define your Plants (=~ Factories if factory_girl) in test/plants.rb
|
15
|
+
|
16
|
+
Example :
|
17
|
+
|
18
|
+
Plant.define :user do |user|
|
19
|
+
user.name="Bart"
|
20
|
+
user.age=800
|
21
|
+
end
|
22
|
+
|
23
|
+
Get it with :
|
24
|
+
|
25
|
+
user = Plant(:user)
|
26
|
+
|
27
|
+
|
28
|
+
<b>Example of tests :</b>
|
29
|
+
|
30
|
+
|
31
|
+
def test___1
|
32
|
+
user = Plant(:user)
|
33
|
+
assert_equal user, User.find #OK
|
34
|
+
assert_equal user, User.find(:first) #OK
|
35
|
+
assert_equal user, User.find(:last) #OK
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def test___2
|
40
|
+
2.times { Plant(:user) }
|
41
|
+
assert_equal 2, User.find(:all).size #OK
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
<b>You can also create a particular plant of user like that:</b>
|
46
|
+
|
47
|
+
user = Plant(:user, :name => "Marie", :age => age)
|
48
|
+
|
49
|
+
== Specification of the class of the fixture definition
|
50
|
+
|
51
|
+
Plant.define :admin, :class => User do |user|
|
52
|
+
user.name = "Bart"
|
53
|
+
user.age = 800
|
54
|
+
end
|
55
|
+
|
56
|
+
== Associations
|
57
|
+
|
58
|
+
Assign fixtures to association in definition of plant :
|
59
|
+
|
60
|
+
Plant.define :profile do |profile|
|
61
|
+
profile.password = "BREIZH!"
|
62
|
+
end
|
63
|
+
|
64
|
+
Plant.define :adress do |adress|
|
65
|
+
adress.number = 12
|
66
|
+
adress.street = "rue de Brest"
|
67
|
+
end
|
68
|
+
|
69
|
+
Plant.define :user do |user|
|
70
|
+
user.name = "Bart"
|
71
|
+
user.age = 800
|
72
|
+
user.profile = Plant.association(:profile)
|
73
|
+
user.adresses = [Plant.association(:adress)]
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
== Definitions with dependent attributes
|
79
|
+
|
80
|
+
If you want to use the value of another attribute in definition, do like that :
|
81
|
+
|
82
|
+
Plant.define :user do |user|
|
83
|
+
user.name = "Marie"
|
84
|
+
user.adresses = [Adress.new(:street => "Rue de #{user.name}")]
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
== Sequences
|
89
|
+
|
90
|
+
As with factory_girl you are able to use sequences, like that :
|
91
|
+
|
92
|
+
Plant.sequence :email do |n|
|
93
|
+
"incognito#{n}@kantena.com"
|
94
|
+
end
|
95
|
+
|
96
|
+
Plant.next(:email) # => "incognito1@kantena.com"
|
97
|
+
Plant.next(:email) # => "incognito2@kantena.com"
|
98
|
+
|
99
|
+
|
100
|
+
== Dependencies
|
101
|
+
|
102
|
+
No dependency.
|
103
|
+
Not tested with rails 3
|
104
|
+
|
105
|
+
|
106
|
+
== Notes
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
<b>Report Bugs here , on github</b>
|
data/lib/factory_boy.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'plant'
|
data/lib/plant.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'stubber'
|
4
|
+
require 'setup'
|
5
|
+
|
6
|
+
module Plant
|
7
|
+
|
8
|
+
@@plants = {}
|
9
|
+
@@pool = {}
|
10
|
+
@@map = {}
|
11
|
+
@@sequences = {}
|
12
|
+
@@stubbed = []
|
13
|
+
|
14
|
+
def self.define symbol, args={}
|
15
|
+
klass = args[:class] || symbol.to_s.camelize.constantize
|
16
|
+
instance = klass.new
|
17
|
+
yield instance if block_given?
|
18
|
+
add_plant(klass, instance)
|
19
|
+
add_plant(symbol, instance) if args[:class]
|
20
|
+
stubs(instance.class)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.stubs klass
|
24
|
+
unless @@stubbed.include?(klass)
|
25
|
+
Plant::Stubber.stubs_find(klass)
|
26
|
+
@@stubbed << klass
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.unstub_find_for_each_class
|
31
|
+
@@stubbed.each {|klass| Plant::Stubber.unstubs_find_for(klass)}
|
32
|
+
@@stubbed = []
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.all
|
36
|
+
@@pool
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.add_plant klass, instance
|
40
|
+
@@plants[klass] = instance
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.plants
|
44
|
+
@@plants
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.reload
|
48
|
+
load "#{RAILS_ROOT}/test/plants.rb" if Plant.plants.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.pool symbol
|
52
|
+
instance = plants[symbol] || plants[symbol.to_s.camelize.constantize]
|
53
|
+
yield instance if block_given?
|
54
|
+
@@pool[instance.class] ||= []
|
55
|
+
@@pool[instance.class] << instance
|
56
|
+
instance
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.destroy
|
60
|
+
@@pool = {}
|
61
|
+
@@plants = {}
|
62
|
+
@@map = {}
|
63
|
+
@@sequences = {}
|
64
|
+
@@stubbed = []
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.sequence symbol, &proc
|
68
|
+
@@sequences[symbol] = {:lambda => proc, :index => 0}
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.next symbol
|
72
|
+
@@sequences[symbol][:lambda].call(@@sequences[symbol][:index] += 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.association symbol
|
76
|
+
Plant.pool(symbol)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
def Plant symbol, args={}
|
82
|
+
Plant.reload
|
83
|
+
Plant.pool(symbol) do |instance|
|
84
|
+
args.each {|key, value| instance.send(key.to_s + '=', value)}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
data/lib/setup.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'mocha' #must put there even if mocha is not used ... else mocha override these aliasings when it's required in test file.
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Test
|
7
|
+
module Unit
|
8
|
+
class TestCase
|
9
|
+
alias_method :original_run, :run
|
10
|
+
|
11
|
+
def run(result,&block)
|
12
|
+
Plant.destroy
|
13
|
+
original_run(result,&block)
|
14
|
+
Plant.unstub_find_for_each_class
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if defined?(ActiveSupport::TestCase)
|
21
|
+
module ActiveSupport
|
22
|
+
class TestCase
|
23
|
+
alias_method :original_run, :run
|
24
|
+
|
25
|
+
def run(result,&block)
|
26
|
+
Plant.destroy
|
27
|
+
original_run(result,&block)
|
28
|
+
Plant.unstub_find_for_each_class
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/stubber.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Plant
|
2
|
+
module Stubber
|
3
|
+
|
4
|
+
def self.stubs_find klass
|
5
|
+
class << klass
|
6
|
+
alias_method :original_find, :find
|
7
|
+
|
8
|
+
def find *args
|
9
|
+
case args.first
|
10
|
+
when :first then Plant::Stubber.find_all(self.name.constantize).first
|
11
|
+
when :last then Plant::Stubber.find_all(self.name.constantize).last
|
12
|
+
when :all then Plant::Stubber.find_all(self.name.constantize)
|
13
|
+
else Plant::Stubber.find(self.name.constantize)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.unstubs_find_for klass
|
20
|
+
class << klass
|
21
|
+
undef_method :find
|
22
|
+
alias_method :find, :original_find
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find_all klass
|
27
|
+
Plant.all[klass] || []
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.find klass
|
31
|
+
return nil unless Plant.all[klass]
|
32
|
+
Plant.all[klass].size == 1 ? Plant.all[klass].first : Plant.all[klass]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/test/help_test.rb
ADDED
data/test/models/user.rb
ADDED
data/test/plants.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Plant.sequence :email do |n|
|
2
|
+
"incognito#{n}@kantena.com"
|
3
|
+
end
|
4
|
+
|
5
|
+
Plant.define :profile do |profile|
|
6
|
+
profile.password = "BREIZH!"
|
7
|
+
end
|
8
|
+
|
9
|
+
Plant.define :adress do |adress|
|
10
|
+
adress.number = 17
|
11
|
+
adress.street = "rue royale"
|
12
|
+
end
|
13
|
+
|
14
|
+
Plant.define :user do |user|
|
15
|
+
user.name = "Zorro"
|
16
|
+
user.age = 800
|
17
|
+
user.profile = Plant.association(:profile)
|
18
|
+
user.adresses = [Plant.association(:adress)]
|
19
|
+
end
|
20
|
+
|
21
|
+
Plant.define :customer do |customer|
|
22
|
+
end
|
23
|
+
|
data/test/test_plant.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'help_test'
|
2
|
+
|
3
|
+
class PlantTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
assert_find_is_unstubbed_for_each_class
|
7
|
+
Plant(:customer)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_define_simple_definition
|
11
|
+
assert customer = Plant(:customer)
|
12
|
+
assert_nil customer.name
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_define_assign_attributes
|
16
|
+
user = Plant(:user)
|
17
|
+
assert_equal "Zorro", user.name
|
18
|
+
assert_equal 800, user.age
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_define_stubs_find_without_parameter
|
22
|
+
user = Plant(:user)
|
23
|
+
assert_equal user, User.find
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_define_stubs_find_with_array_result
|
27
|
+
2.times { Plant(:user) }
|
28
|
+
assert_equal 2, User.find(:all).size
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_define_with_association_has_one
|
32
|
+
user = Plant(:user)
|
33
|
+
profile = Profile.find
|
34
|
+
assert_equal profile, user.profile
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_define_with_association_has_many
|
38
|
+
user = Plant(:user)
|
39
|
+
assert adresses = user.adresses
|
40
|
+
adress = Adress.find
|
41
|
+
assert_equal adress, user.adresses.first
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_stubs_find_with_option_all
|
45
|
+
user = Plant(:user)
|
46
|
+
users = User.find(:all)
|
47
|
+
assert_equal [user], users
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_find_all_must_return_an_empty_array_if_no_object
|
51
|
+
users = User.find(:all)
|
52
|
+
assert_equal [], users
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_stubs_find_with_option_first
|
56
|
+
users = 3.times.map { Plant(:user) }
|
57
|
+
assert_equal users.first, User.find(:first)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_stubs_find_with_option_last
|
61
|
+
users = 3.times.map { Plant(:user) }
|
62
|
+
assert_equal users.last, User.find(:last)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_mocha_is_not_overidden_with_plant_setup
|
66
|
+
Plant.expects(:pool).once
|
67
|
+
Plant(:user)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_create_plant_with_hash_for_values
|
71
|
+
adress = Plant(:adress)
|
72
|
+
user = Plant(:user, :name => "Marie", :adresses => [adress])
|
73
|
+
assert_equal "Marie", user.name
|
74
|
+
assert_equal adress, user.adresses.first
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_define_with_class_option
|
78
|
+
Plant.define :marie, :class => User do |peter|
|
79
|
+
peter.name = "Marie"
|
80
|
+
peter.adresses = [Adress.new(:street => "Rue de Brest")]
|
81
|
+
end
|
82
|
+
marie = Plant(:marie)
|
83
|
+
assert_equal "Marie", marie.name
|
84
|
+
assert_equal "Rue de Brest", marie.adresses.first.street
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_plants_are_reloaded_and_4_plants_are_defined
|
88
|
+
assert_equal 4, Plant.plants.size
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_define_with_dependent_attribute
|
92
|
+
Plant.define :user do |user|
|
93
|
+
user.name = "Marie"
|
94
|
+
user.adresses = [Adress.new(:street => "Rue de #{user.name}")]
|
95
|
+
end
|
96
|
+
assert_equal "Rue de Marie", Plant(:user).adresses.first.street
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_plant_sequences
|
100
|
+
assert_equal "incognito1@kantena.com", Plant.next(:email)
|
101
|
+
assert_equal "incognito2@kantena.com", Plant.next(:email)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def assert_find_is_unstubbed_for_each_class
|
107
|
+
[Adress, Customer, Profile, User].each {|klass| assert_equal "original_find", klass.find }
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: factory_boy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Philippe Cantin
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-01 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Factory Girl with database accesses stubbed
|
23
|
+
email:
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.rdoc
|
30
|
+
files:
|
31
|
+
- lib/factory_boy.rb
|
32
|
+
- lib/plant.rb
|
33
|
+
- lib/setup.rb
|
34
|
+
- lib/stubber.rb
|
35
|
+
- README.rdoc
|
36
|
+
- test/help_test.rb
|
37
|
+
- test/models/adress.rb
|
38
|
+
- test/models/customer.rb
|
39
|
+
- test/models/profile.rb
|
40
|
+
- test/models/user.rb
|
41
|
+
- test/plants.rb
|
42
|
+
- test/test_plant.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/anoiaque/factory_boy
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
hash: 3
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.7
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Create fixtures for unit testing as in Factory Girl but without database usage.
|
77
|
+
test_files:
|
78
|
+
- test/help_test.rb
|
79
|
+
- test/models/adress.rb
|
80
|
+
- test/models/customer.rb
|
81
|
+
- test/models/profile.rb
|
82
|
+
- test/models/user.rb
|
83
|
+
- test/plants.rb
|
84
|
+
- test/test_plant.rb
|