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