cranky 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 832320f9e104372957157b3cef6c0d81592a6b66
4
+ data.tar.gz: 6560e13c455a033fa20f11041c065bf13b95f7ec
5
+ SHA512:
6
+ metadata.gz: 82347e3df728a862aec73692225e6e0344df1503d0ff117ca4f8bff366f8626e7fbc027d7322c32f73b95d11de6a0bd0bbe1c895a1116141e5fbb5c45238e62f
7
+ data.tar.gz: a5c223a0a63ad0231fb342c5f20fcd17fbdd438431a05f78fff8fa25fbc00b163f8b1bb6bea24166e36070bab98d7ca3f88812987de034d944aa49f3a251f9e8
data/Gemfile CHANGED
@@ -3,11 +3,10 @@ source "http://gemcutter.org"
3
3
  group :development do
4
4
  gem "rake"
5
5
  gem "gemcutter"
6
- gem "ruby-debug19", :require => 'ruby-debug'
7
6
  end
8
7
 
9
8
  group :test do
10
9
  gem "rspec"
11
- gem "rcov"
10
+ gem "simplecov", require: false
12
11
  end
13
12
 
data/Gemfile.lock CHANGED
@@ -1,14 +1,11 @@
1
1
  GEM
2
2
  remote: http://gemcutter.org/
3
3
  specs:
4
- archive-tar-minitar (0.5.2)
5
- columnize (0.3.4)
6
4
  diff-lcs (1.1.2)
5
+ docile (1.1.5)
7
6
  gemcutter (0.7.0)
8
- linecache19 (0.5.12)
9
- ruby_core_source (>= 0.1.4)
7
+ json (1.8.3)
10
8
  rake (0.9.2)
11
- rcov (0.9.9)
12
9
  rspec (2.6.0)
13
10
  rspec-core (~> 2.6.0)
14
11
  rspec-expectations (~> 2.6.0)
@@ -17,16 +14,11 @@ GEM
17
14
  rspec-expectations (2.6.0)
18
15
  diff-lcs (~> 1.1.2)
19
16
  rspec-mocks (2.6.0)
20
- ruby-debug-base19 (0.11.25)
21
- columnize (>= 0.3.1)
22
- linecache19 (>= 0.5.11)
23
- ruby_core_source (>= 0.1.4)
24
- ruby-debug19 (0.11.6)
25
- columnize (>= 0.3.1)
26
- linecache19 (>= 0.5.11)
27
- ruby-debug-base19 (>= 0.11.19)
28
- ruby_core_source (0.1.5)
29
- archive-tar-minitar (>= 0.5.2)
17
+ simplecov (0.11.2)
18
+ docile (~> 1.1.0)
19
+ json (~> 1.8)
20
+ simplecov-html (~> 0.10.0)
21
+ simplecov-html (0.10.0)
30
22
 
31
23
  PLATFORMS
32
24
  ruby
@@ -34,6 +26,8 @@ PLATFORMS
34
26
  DEPENDENCIES
35
27
  gemcutter
36
28
  rake
37
- rcov
38
29
  rspec
39
- ruby-debug19
30
+ simplecov
31
+
32
+ BUNDLED WITH
33
+ 1.12.2
data/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # Cranky
2
+
3
+ Cranky is a fixtures replacement inspired by the excellent Factory Girl but with easier syntax and no external
4
+ dependencies, it will work straight out of the box with rails 10.
5
+
6
+ In short use this if you want to quickly and naturally create factory methods that you feel 100% in control of.
7
+
8
+ ## Install
9
+
10
+ First install the gem...
11
+
12
+ ~~~
13
+ gem install cranky
14
+ ~~~
15
+
16
+ Or with bundler...
17
+
18
+ ~~~ruby
19
+ # Gemfile
20
+ gem "cranky"
21
+ ~~~
22
+
23
+ Then in your spec_helper.rb ...
24
+
25
+ ~~~ruby
26
+ # spec_helper.rb
27
+ require "cranky"
28
+ require "factories/my_factories"
29
+ ~~~
30
+
31
+ The above assumes that you have created your factory methods in a file called my_factories.rb in the spec/factories directory.
32
+ You can create as many different factory files as you want, just require them in the same way.
33
+
34
+ ## In a Nutshell
35
+
36
+ The API to use in your tests is:
37
+
38
+ ~~~ruby
39
+ crank(:user) # Build a user instance without saving
40
+ crank!(:user) # Build and save a user instance
41
+ crank(:user, :name => "Ian") # Override a default attribute value
42
+ crank(:user_attrs) # Return a set of valid attributes rather than the object
43
+ ~~~
44
+
45
+ Alternatively the Factory Girl syntax also works and therefore Cranky can drop into tests already written for that framework...
46
+
47
+ ~~~ruby
48
+ Factory.build(:user) # Build a user instance without saving
49
+ Factory.create(:user) # Build and save a user instance
50
+ Factory.build(:user, :name => "Ian") # Override a default attribute value
51
+ Factory.attributes_for(:user) # Return a set of valid attributes rather than the object
52
+ ~~~
53
+
54
+ Or if you're coming from Machinist, you can make your Cranky factories drop into your existing tests by setting up make and make! methods as [shown here](http://gist.github.com/525653).
55
+
56
+ Cranky has a nice debug option (rails only) to warn you when your factory is broken, recommend you do this for your first spec...
57
+
58
+ ~~~ruby
59
+ describe User do
60
+ it "should have a working factory" do
61
+ # This will raise an error and report the validation errors should they occur
62
+ Factory.debug(:user).should be_valid
63
+ end
64
+ end
65
+ ~~~
66
+
67
+ Cranky allows you to build factories via std Ruby methods, like this...
68
+
69
+ ~~~ruby
70
+ # factories/my_factories.rb
71
+ class Cranky::Factory # Your factory must reopen Cranky::Factory
72
+
73
+ # Simple factory method to create a user instance, you would call this via Factory.build(:user)
74
+ def user
75
+ # Define attributes via a hash, generate the values any way you want
76
+ define :name => "Jimmy",
77
+ :email => "jimmy#{n}@home.com", # An 'n' counter method is available to help make things unique
78
+ :role => "pleb",
79
+ :address => default_address # Call your own helper methods to wire up your associations
80
+ end
81
+
82
+ # Easily create variations via the inherit helper, callable via Factory.build(:admin)
83
+ def admin
84
+ inherit(:user, :role => "admin")
85
+ end
86
+
87
+ # Return a default address if it already exists, or call the address factory to make one
88
+ def default_address
89
+ @default_address ||= create(:address)
90
+ end
91
+
92
+ # Alternatively loose the DSL altogether and define the factory yourself, still callable via Factory.build(:address)
93
+ def address
94
+ a = Address.new
95
+ a.street = "192 Broadway"
96
+ a.city = options[:city] || "New York" # You can get any caller overrides via the options hash
97
+ a # Only rule is the method must return the generated object
98
+ end
99
+
100
+ end
101
+ ~~~
102
+
103
+ # Details
104
+
105
+ ## Define Your Factories
106
+
107
+ This is where Cranky really shines, if you can create Ruby methods you can pretty much create your factories without having to refer to the syntax documentation ever again.
108
+
109
+ The only rules are:
110
+
111
+ 1. Your factory must reopen the Cranky::Factory class
112
+ 2. Your factory method must return the object you wanted to create
113
+ 3. You can access the overrides passed in via options[:key]. (not really a rule!)
114
+
115
+ So for example to create a simple user factory...
116
+
117
+ ~~~ruby
118
+ # factories/my_factories.rb
119
+ class Cranky::Factory
120
+
121
+ # Simple factory method to create a user instance, you would call this via Factory.build(:user)
122
+ def user
123
+ u = User.new
124
+ u.name = options[:name] || "Jimmy" # Use the passed in name if present, or the default
125
+ u.email = options[:email] || "jimmy#{n}@home.com" # Give each user a unique email address
126
+ u.role = options[:role] || "pleb"
127
+ u
128
+ end
129
+
130
+ end
131
+ ~~~
132
+
133
+ Now of course you are working in straight Ruby here, so you can extend this any way you want as long as you follow the above rules.
134
+
135
+ For example here it is with the capability to automatically create a default address association...
136
+
137
+ ~~~ruby
138
+ # factories/my_factories.rb
139
+ class Cranky::Factory
140
+
141
+ # Return the default address if it already exists, or call the address factory to make one
142
+ def default_address
143
+ @default_address ||= create(:address)
144
+ end
145
+
146
+ def user
147
+ u = User.new
148
+ u.name = options[:name] || "Jimmy"
149
+ u.email = options[:email] || "jimmy#{n}@home.com"
150
+ u.role = options[:role] || "pleb"
151
+ u.address = default_address
152
+ u
153
+ end
154
+
155
+ # Create the address factory in the same way
156
+
157
+ end
158
+ ~~~
159
+
160
+ Quite often the database will be cleared between tests but the instance variable in the factory will not necessarily be reset which could lead to problems if the tests check for the associated record in the database.
161
+ So a nice tip is to implement default associations like this (assuming you're using Rails)...
162
+
163
+ ~~~ruby
164
+ # Return the default address if it already exists, or call the address factory to make one
165
+ def default_address
166
+ # If the default address exists, but has been cleared from the database...
167
+ @default_address = nil if @default_address && !Address.exists?(@default_address.id)
168
+ @default_address ||= create(:address)
169
+ end
170
+ ~~~
171
+
172
+ You can pass additional arguments to your factories via the overrides hash...
173
+
174
+ ~~~ruby
175
+ Factory.build(:user, :new_address => true)
176
+
177
+ def user
178
+ u = User.new
179
+ u.name = options[:name] || "Jimmy"
180
+ u.email = options[:email] || "jimmy#{n}@home.com"
181
+ u.role = options[:role] || "pleb"
182
+ u.address = options[:new_address] ? create(:address) : default_address
183
+ u
184
+ end
185
+ ~~~
186
+
187
+ You can use traits...
188
+
189
+ ~~~ruby
190
+ Factory.build(:user, traits: [:admin, :manager])
191
+
192
+ def user
193
+ u = User.new
194
+ u.name = options[:name] || "Jimmy"
195
+ u.email = options[:email] || "jimmy#{n}@home.com"
196
+ u.role = options[:role] || "pleb"
197
+ u.address = options[:new_address] ? create(:address) : default_address
198
+ u
199
+ end
200
+
201
+ def apply_trait_admin_to_user(user)
202
+ user.roles << :admin
203
+ end
204
+
205
+ def apply_trait_manager_to_user(user)
206
+ user.roles << :manager
207
+ end
208
+ ~~~
209
+
210
+ ## Helpers
211
+
212
+ Of course its nice to get some help...
213
+
214
+ ### Define
215
+
216
+ Most of your factories are likely to simply define a list of mimimum attribute values, use the define helper for this.
217
+
218
+ ~~~ruby
219
+ # The user factory re-written using the define helper
220
+ def user
221
+ define :name => "Jimmy",
222
+ :email => "jimmy#{n}@home.com",
223
+ :role => "pleb",
224
+ :address => default_address
225
+ end
226
+ ~~~
227
+
228
+ Note that you don't have to worry about handling the overrides here, they will be applied automatically if present, just define the defaults.
229
+
230
+ The define argument is just a regular hash, you have complete freedom to choose how to generate the values to be passed into it.
231
+
232
+ If you like you can generate attributes with a block:
233
+
234
+ ~~~ruby
235
+ def user
236
+ define :name => "Jimmy",
237
+ :email => lambda{|u| "#{u.name.downcase}@home.com"},
238
+ :role => "pleb",
239
+ :address => default_address
240
+ end
241
+ ~~~
242
+
243
+ The define method will return the object, you can grab this for additional manipulation as you would expect...
244
+
245
+ ~~~ruby
246
+ def user
247
+ u = define :name => "Jimmy",
248
+ :email => "jimmy#{n}@home.com",
249
+ :role => "pleb",
250
+ :address => default_address
251
+ u.do_something
252
+ u # Remember to return it at the end
253
+ end
254
+ ~~~
255
+
256
+ If for any reason you want to have your factory method named differently from the model it instantiates you can pass in a :class attribute to the define method...
257
+
258
+ ~~~ruby
259
+ # Called via Factory.create(:jimmy)
260
+ def jimmy
261
+ u = define :class => :user,
262
+ :name => "Jimmy",
263
+ :email => "jimmy#{n}@home.com",
264
+ :role => "pleb",
265
+ :address => default_address
266
+ end
267
+ ~~~
268
+
269
+ ### Inherit
270
+
271
+ You can inherit from other factories via the inherit method. So for example to create an admin user you might do...
272
+
273
+ ~~~ruby
274
+ # Called via Factory.create(:admin)
275
+ def admin
276
+ inherit(:user, :role => "admin") # Pass in any attribute overrides you want
277
+ end
278
+ ~~~
279
+
280
+ ### Unique Attributes (n)
281
+
282
+ If you want to generate unique attributes you can call the n method which will automatically increment the next time it is called.
283
+
284
+ Note that every time n is called it will increment, it does not implement a unique counter per attribute.
285
+
286
+ ### Reset
287
+
288
+ Clear all instance variables in the factory. This may be useful to run between tests depending on your factory logic...
289
+
290
+ ~~~ruby
291
+ before(:each) do
292
+ Factory.reset
293
+ end
294
+ ~~~
295
+
296
+ ### Debug
297
+
298
+ Sometimes it is useful to be warned that your factory is generating invalid instances (although quite often your tests may intentionally generate invalid instances, so use this with care). By turning on debug the Factory will raise an error if the generated instance is invalid...
299
+
300
+ ~~~ruby
301
+ Factory.debug(:user) # A replacement for Factory.build, with validation warnings enabled
302
+ Factory.debug!(:user) # Likewise for Factory.create
303
+ ~~~
304
+
305
+ Note that this relies on the instance having a valid? method, so in practice this may only work with Rails.
306
+
307
+ ### Attributes For
308
+
309
+ Returns the attributes that would be applied by a given factory method...
310
+
311
+ ~~~ruby
312
+ valid_attributes = Factory.attributes_for(:user)
313
+ ~~~
314
+
315
+ Requires that the instance has an attributes method, so again may only work under Rails.
316
+
317
+ ## Additional Features
318
+
319
+ Want any? Feel free to let me know.
320
+
321
+ ## Thanks
322
+
323
+ Cranky was inspired by [factory_girl](http://github.com/thoughtbot/factory_girl) and [miniskirt](http://gist.github.com/273579).
324
+
325
+ Thanks to both.
326
+
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ $:.unshift File.expand_path("../lib", __FILE__)
2
+
3
+ require 'cranky'
4
+ require 'rubygems'
5
+ require 'rspec/core'
6
+ require 'rspec/core/rake_task'
7
+
8
+ desc "Run specs"
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.pattern = ("spec/**/*_spec.rb")
11
+ end
12
+
13
+ task :default => :spec
14
+
15
+ task :release_tag do
16
+ system "git commit -a -m 'Release #{Cranky::VERSION}'"
17
+ system "git tag -a v#{Cranky::VERSION} -m 'version #{Cranky::VERSION}'"
18
+ end
19
+
20
+ # Push to github
21
+ desc "Push to Github"
22
+ task :push do
23
+ system "git push --tags origin master"
24
+ end
25
+
26
+ desc "Build the gem"
27
+ task :build do
28
+ system "bundle exec gem build cranky.gemspec"
29
+ end
30
+
31
+ desc "Release version #{Cranky::VERSION}"
32
+ task :release => [:build, :release_tag, :push] do
33
+ system "bundle exec gem push cranky-#{Cranky::VERSION}.gem"
34
+ end
35
+
36
+
@@ -58,6 +58,16 @@ module Cranky
58
58
 
59
59
  private
60
60
 
61
+ def apply_traits(what, item)
62
+ Array(options[:traits]).each do |t|
63
+ trait_method_name = "apply_trait_#{t}_to_#{what}"
64
+ fail("Invalid trait '#{t}'! No method '#{trait_method_name}' is defined.") unless respond_to?(trait_method_name)
65
+ send(trait_method_name, item)
66
+ end
67
+
68
+ item
69
+ end
70
+
61
71
  def n
62
72
  @n += 1
63
73
  end
@@ -71,6 +81,7 @@ module Cranky
71
81
  item = "TBD"
72
82
  new_job(what, overrides) do
73
83
  item = self.send(what) # Invoke the factory method
84
+ item = apply_traits(what, item)
74
85
  end
75
86
  item
76
87
  end
@@ -1,3 +1,3 @@
1
1
  module Cranky
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
data/spec/cranky_spec.rb CHANGED
@@ -127,6 +127,15 @@ describe "The Cranky factory" do
127
127
  Factory.build(:user_hash, :role => :admin)[:role].should == :admin
128
128
  end
129
129
 
130
+ it "is capable of using traits" do
131
+ user = Factory.build(:user_manually, :traits => :manager)
132
+ user.role.should == :manager
133
+ end
134
+
135
+ it "raises exception if trait method is undefined" do
136
+ lambda { Factory.build(:user_by_define, :traits => :manager) }.should raise_error("Invalid trait 'manager'! No method 'apply_trait_manager_to_user_by_define' is defined.")
137
+ end
138
+
130
139
  specify "attributes are not assigned when they have the value :skip" do
131
140
  crank(:user, :name => :skip).name.should_not be
132
141
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,11 @@
1
- require 'rubygems'
2
- require 'rspec'
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
3
4
  require 'cranky'
4
5
 
6
+ RSpec.configure do |config|
7
+ config.expect_with(:rspec) { |c| c.syntax = :should }
8
+ end
5
9
 
6
10
  class TestClass
7
11
  attr_accessor :valid
@@ -91,7 +95,8 @@ class Cranky::Factory
91
95
  :name => "Fred",
92
96
  :role => :user
93
97
  end
94
- end
95
-
96
-
97
98
 
99
+ def apply_trait_manager_to_user_manually(user)
100
+ user.role = :manager
101
+ end
102
+ end
metadata CHANGED
@@ -1,78 +1,56 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: cranky
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 3
8
- - 1
9
- version: 0.3.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
10
5
  platform: ruby
11
- authors:
6
+ authors:
12
7
  - Stephen McGinty
13
8
  autorequire:
14
9
  bindir: bin
15
10
  cert_chain: []
16
-
17
- date: 2011-10-22 00:00:00 +01:00
18
- default_executable:
11
+ date: 2016-05-30 00:00:00.000000000 Z
19
12
  dependencies: []
20
-
21
- description: A very light yet powerful test factory framework with an extremely clean syntax that makes it very easy to define your factories.
22
- email: ginty@hyperdecade.com
13
+ description: A very light yet powerful test factory framework with an extremely clean
14
+ syntax that makes it very easy to define your factories.
15
+ email: stephen.f.mcginty@gmail.com
23
16
  executables: []
24
-
25
17
  extensions: []
26
-
27
18
  extra_rdoc_files: []
28
-
29
- files:
30
- - lib/cranky/factory.rb
31
- - lib/cranky/version.rb
32
- - lib/cranky/job.rb
33
- - lib/cranky.rb
34
- - spec/spec_helper.rb
35
- - spec/cranky_spec.rb
19
+ files:
36
20
  - CHANGELOG.md
37
21
  - Gemfile
38
22
  - Gemfile.lock
39
- - README.rdoc
40
23
  - LICENSE
24
+ - README.md
25
+ - Rakefile
41
26
  - init.rb
42
- has_rdoc: true
27
+ - lib/cranky.rb
28
+ - lib/cranky/factory.rb
29
+ - lib/cranky/job.rb
30
+ - lib/cranky/version.rb
31
+ - spec/cranky_spec.rb
32
+ - spec/spec_helper.rb
43
33
  homepage: http://github.com/ginty/cranky
44
34
  licenses: []
45
-
35
+ metadata: {}
46
36
  post_install_message:
47
37
  rdoc_options: []
48
-
49
- require_paths:
38
+ require_paths:
50
39
  - lib
51
- required_ruby_version: !ruby/object:Gem::Requirement
52
- none: false
53
- requirements:
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
54
42
  - - ">="
55
- - !ruby/object:Gem::Version
56
- hash: -570131409
57
- segments:
58
- - 0
59
- version: "0"
60
- required_rubygems_version: !ruby/object:Gem::Requirement
61
- none: false
62
- requirements:
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
63
47
  - - ">="
64
- - !ruby/object:Gem::Version
65
- segments:
66
- - 1
67
- - 3
68
- - 4
48
+ - !ruby/object:Gem::Version
69
49
  version: 1.3.4
70
50
  requirements: []
71
-
72
51
  rubyforge_project:
73
- rubygems_version: 1.3.7
52
+ rubygems_version: 2.4.5
74
53
  signing_key:
75
- specification_version: 3
54
+ specification_version: 4
76
55
  summary: A very light yet powerful test factory framework.
77
56
  test_files: []
78
-
data/README.rdoc DELETED
@@ -1,265 +0,0 @@
1
- = Cranky
2
-
3
- Cranky is a fixtures replacement inspired by the excellent Factory Girl but with easier syntax and no external
4
- dependencies, it will work straight out of the box with rails 10.
5
-
6
- In short use this if you want to quickly and naturally create factory methods that you feel 100% in control of.
7
-
8
- == Install
9
-
10
- First install the gem...
11
-
12
- gem install cranky
13
-
14
- Or with bundler...
15
-
16
- # Gemfile
17
- gem "cranky"
18
-
19
- Then in your spec_helper.rb ...
20
-
21
- # spec_helper.rb
22
- require "cranky"
23
- require "factories/my_factories"
24
-
25
- The above assumes that you have created your factory methods in a file called my_factories.rb in the spec/factories directory.
26
- You can create as many different factory files as you want, just require them in the same way.
27
-
28
- == In a Nutshell
29
-
30
- The API to use in your tests is:
31
-
32
- crank(:user) # Build a user instance without saving
33
- crank!(:user) # Build and save a user instance
34
- crank(:user, :name => "Ian") # Override a default attribute value
35
- crank(:user_attrs) # Return a set of valid attributes rather than the object
36
-
37
- Alternatively the Factory Girl syntax also works and therefore Cranky can drop into tests already written for that framework...
38
-
39
- Factory.build(:user) # Build a user instance without saving
40
- Factory.create(:user) # Build and save a user instance
41
- Factory.build(:user, :name => "Ian") # Override a default attribute value
42
- Factory.attributes_for(:user) # Return a set of valid attributes rather than the object
43
-
44
- Or if you're coming from Machinist, you can make your Cranky factories drop into your existing tests by setting up make and make! methods as shown here.[http://gist.github.com/525653]
45
-
46
- Cranky has a nice debug option (rails only) to warn you when your factory is broken, recommend you do this for your first spec...
47
-
48
- describe User do
49
- it "should have a working factory" do
50
- # This will raise an error and report the validation errors should they occur
51
- Factory.debug(:user).should be_valid
52
- end
53
- end
54
-
55
- Cranky allows you to build factories via std Ruby methods, like this...
56
-
57
- # factories/my_factories.rb
58
- class Cranky::Factory # Your factory must reopen Cranky::Factory
59
-
60
- # Simple factory method to create a user instance, you would call this via Factory.build(:user)
61
- def user
62
- # Define attributes via a hash, generate the values any way you want
63
- define :name => "Jimmy",
64
- :email => "jimmy#{n}@home.com", # An 'n' counter method is available to help make things unique
65
- :role => "pleb",
66
- :address => default_address # Call your own helper methods to wire up your associations
67
- end
68
-
69
- # Easily create variations via the inherit helper, callable via Factory.build(:admin)
70
- def admin
71
- inherit(:user, :role => "admin")
72
- end
73
-
74
- # Return a default address if it already exists, or call the address factory to make one
75
- def default_address
76
- @default_address ||= create(:address)
77
- end
78
-
79
- # Alternatively loose the DSL altogether and define the factory yourself, still callable via Factory.build(:address)
80
- def address
81
- a = Address.new
82
- a.street = "192 Broadway"
83
- a.city = options[:city] || "New York" # You can get any caller overrides via the options hash
84
- a # Only rule is the method must return the generated object
85
- end
86
-
87
- end
88
-
89
- = Details
90
-
91
- == Define Your Factories
92
-
93
- This is where Cranky really shines, if you can create Ruby methods you can pretty much create your factories without having to refer to the syntax documentation ever again.
94
-
95
- The only rules are:
96
-
97
- 1. Your factory must reopen the Cranky::Factory class
98
- 2. Your factory method must return the object you wanted to create
99
- 3. You can access the overrides passed in via options[:key] (not really a rule!)
100
-
101
- So for example to create a simple user factory...
102
-
103
- # factories/my_factories.rb
104
- class Cranky::Factory
105
-
106
- # Simple factory method to create a user instance, you would call this via Factory.build(:user)
107
- def user
108
- u = User.new
109
- u.name = options[:name] || "Jimmy" # Use the passed in name if present, or the default
110
- u.email = options[:email] || "jimmy#{n}@home.com" # Give each user a unique email address
111
- u.role = options[:role] || "pleb"
112
- u
113
- end
114
-
115
- end
116
-
117
- Now of course you are working in straight Ruby here, so you can extend this any way you want as long as you follow the above rules.
118
-
119
- For example here it is with the capability to automatically create a default address association...
120
-
121
- # factories/my_factories.rb
122
- class Cranky::Factory
123
-
124
- # Return the default address if it already exists, or call the address factory to make one
125
- def default_address
126
- @default_address ||= create(:address)
127
- end
128
-
129
- def user
130
- u = User.new
131
- u.name = options[:name] || "Jimmy"
132
- u.email = options[:email] || "jimmy#{n}@home.com"
133
- u.role = options[:role] || "pleb"
134
- u.address = default_address
135
- u
136
- end
137
-
138
- ... # Create the address factory in the same way
139
-
140
- end
141
-
142
- Quite often the database will be cleared between tests but the instance variable in the factory will not necessarily be reset which could lead to problems if the tests check for the associated record in the database.
143
- So a nice tip is to implement default associations like this (assuming you're using Rails)...
144
-
145
- # Return the default address if it already exists, or call the address factory to make one
146
- def default_address
147
- # If the default address exists, but has been cleared from the database...
148
- @default_address = nil if @default_address && !Address.exists?(@default_address.id)
149
- @default_address ||= create(:address)
150
- end
151
-
152
- You can pass additional arguments to your factories via the overrides hash...
153
-
154
- Factory.build(:user, :new_address => true)
155
-
156
- def user
157
- u = User.new
158
- u.name = options[:name] || "Jimmy"
159
- u.email = options[:email] || "jimmy#{n}@home.com"
160
- u.role = options[:role] || "pleb"
161
- u.address = options[:new_address] ? create(:address) : default_address
162
- u
163
- end
164
-
165
- == Helpers
166
-
167
- Of course its nice to get some help...
168
-
169
- === Define
170
-
171
- Most of your factories are likely to simply define a list of mimimum attribute values, use the define helper for this.
172
-
173
- # The user factory re-written using the define helper
174
- def user
175
- define :name => "Jimmy",
176
- :email => "jimmy#{n}@home.com",
177
- :role => "pleb",
178
- :address => default_address
179
- end
180
-
181
- Note that you don't have to worry about handling the overrides here, they will be applied automatically if present, just define the defaults.
182
-
183
- The define argument is just a regular hash, you have complete freedom to choose how to generate the values to be passed into it.
184
-
185
- If you like you can generate attributes with a block:
186
-
187
- def user
188
- define :name => "Jimmy",
189
- :email => lambda{|u| "#{u.name.downcase}@home.com"},
190
- :role => "pleb",
191
- :address => default_address
192
- end
193
-
194
- The define method will return the object, you can grab this for additional manipulation as you would expect...
195
-
196
- def user
197
- u = define :name => "Jimmy",
198
- :email => "jimmy#{n}@home.com",
199
- :role => "pleb",
200
- :address => default_address
201
- u.do_something
202
- u # Remember to return it at the end
203
- end
204
-
205
- If for any reason you want to have your factory method named differently from the model it instantiates you can pass in a :class attribute to the define method...
206
-
207
- # Called via Factory.create(:jimmy)
208
- def jimmy
209
- u = define :class => :user,
210
- :name => "Jimmy",
211
- :email => "jimmy#{n}@home.com",
212
- :role => "pleb",
213
- :address => default_address
214
- end
215
-
216
- === Inherit
217
-
218
- You can inherit from other factories via the inherit method. So for example to create an admin user you might do...
219
-
220
- # Called via Factory.create(:admin)
221
- def admin
222
- inherit(:user, :role => "admin") # Pass in any attribute overrides you want
223
- end
224
-
225
- === Unique Attributes (n)
226
-
227
- If you want to generate unique attributes you can call the n method which will automatically increment the next time it is called.
228
-
229
- Note that every time n is called it will increment, it does not implement a unique counter per attribute.
230
-
231
- === Reset
232
-
233
- Clear all instance variables in the factory. This may be useful to run between tests depending on your factory logic...
234
-
235
- before(:each) do
236
- Factory.reset
237
- end
238
-
239
- === Debug
240
-
241
- Sometimes it is useful to be warned that your factory is generating invalid instances (although quite often your tests may intentionally generate invalid instances, so use this with care). By turning on debug the Factory will raise an error if the generated instance is invalid...
242
-
243
- Factory.debug(:user) # A replacement for Factory.build, with validation warnings enabled
244
- Factory.debug!(:user) # Likewise for Factory.create
245
-
246
- Note that this relies on the instance having a valid? method, so in practice this may only work with Rails.
247
-
248
- === Attributes For
249
-
250
- Returns the attributes that would be applied by a given factory method...
251
-
252
- valid_attributes = Factory.attributes_for(:user)
253
-
254
- Requires that the instance has an attributes method, so again may only work under Rails.
255
-
256
- == Additional Features
257
-
258
- Want any? Feel free to let me know.
259
-
260
- == Thanks
261
-
262
- Cranky was inspired by factory_girl[http://github.com/thoughtbot/factory_girl] and miniskirt[http://gist.github.com/273579].
263
-
264
- Thanks to both.
265
-