flexmock 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +10 -1
  2. data/README +390 -209
  3. data/Rakefile +31 -10
  4. data/doc/GoogleExample.rdoc +275 -0
  5. data/doc/releases/flexmock-0.6.0.rdoc +136 -0
  6. data/lib/flexmock.rb +3 -1160
  7. data/lib/flexmock/argument_matchers.rb +57 -0
  8. data/lib/flexmock/argument_types.rb +42 -0
  9. data/lib/flexmock/base.rb +22 -0
  10. data/lib/flexmock/composite.rb +10 -0
  11. data/lib/flexmock/core.rb +206 -0
  12. data/lib/flexmock/core_class_methods.rb +92 -0
  13. data/lib/flexmock/default_framework_adapter.rb +31 -0
  14. data/lib/flexmock/expectation.rb +334 -0
  15. data/lib/flexmock/expectation_director.rb +59 -0
  16. data/lib/flexmock/mock_container.rb +159 -0
  17. data/lib/flexmock/noop.rb +13 -0
  18. data/lib/flexmock/partial_mock.rb +226 -0
  19. data/lib/flexmock/recorder.rb +71 -0
  20. data/lib/flexmock/rspec.rb +34 -0
  21. data/lib/flexmock/test_unit.rb +32 -0
  22. data/lib/flexmock/test_unit_integration.rb +53 -0
  23. data/lib/flexmock/validators.rb +77 -0
  24. data/test/rspec_integration/integration_spec.rb +36 -0
  25. data/test/test_container_methods.rb +119 -0
  26. data/test/test_default_framework_adapter.rb +39 -0
  27. data/test/test_example.rb +1 -1
  28. data/test/test_extended_should_receive.rb +63 -0
  29. data/test/test_mock.rb +1 -1
  30. data/test/test_naming.rb +1 -1
  31. data/test/{test_any_instance.rb → test_new_instances.rb} +15 -8
  32. data/test/{test_stubbing.rb → test_partial_mock.rb} +44 -44
  33. data/test/test_record_mode.rb +1 -1
  34. data/test/test_samples.rb +6 -8
  35. data/test/test_should_receive.rb +7 -3
  36. data/test/test_tu_integration.rb +1 -1
  37. data/test/test_unit_integration/test_auto_test_unit.rb +34 -0
  38. metadata +30 -5
  39. data/test/test_class_interception.rb +0 -140
data/CHANGELOG CHANGED
@@ -2,7 +2,16 @@
2
2
 
3
3
  = Changes for FlexMock
4
4
 
5
- == Pre Version 0.5.1
5
+ == Version 0.6.0
6
+
7
+ * Dropped class interception.
8
+ * Refactored into more granular classes.
9
+ * Added RSpec integration.
10
+ * Added hash expectations to flexmock() and should_expect().
11
+ * Integrated partial mocks into the flexmock() methods.
12
+ * Allow non-block configuration of new_instances.
13
+
14
+ == Version 0.5.1
6
15
 
7
16
  * Changed the name of any_instance to new_instances.
8
17
  Deprecated any_instance.
data/README CHANGED
@@ -3,13 +3,13 @@
3
3
  FlexMock is a simple, but flexible, mock object library for Ruby unit
4
4
  testing.
5
5
 
6
- Version :: 0.5.1
6
+ Version :: 0.6.0
7
7
 
8
8
  = Links
9
9
 
10
- <b>Documents</b> :: http://onestepback.org/software/flexmock
10
+ <b>Documents</b> :: http://flexmock.rubyforge.org
11
11
  <b>RubyGems</b> :: Install with: <b>gem install flexmock</b>
12
- <b>Download</b> :: Download from RubyForge at http://rubyforge.org/frs/?group_id=170
12
+ <b>Download</b> :: Download from RubyForge at http://rubyforge.org/frs/?group_id=3433 (pre 0.6.0 versions may be found at http://rubyforge.org/frs/?group_id=170)
13
13
 
14
14
  == Installation
15
15
 
@@ -27,7 +27,7 @@ mock object that responds to the +read_temperature+ message.
27
27
  Here's the complete example:
28
28
 
29
29
  require 'test/unit'
30
- require 'flexmock'
30
+ require 'flexmock/test_unit'
31
31
 
32
32
  class TemperatureSampler
33
33
  def initialize(sensor)
@@ -35,149 +35,299 @@ Here's the complete example:
35
35
  end
36
36
 
37
37
  def average_temp
38
- total = (0...3).collect { @sensor.read_temperature }.inject { |i, s| i + s }
38
+ total = (0...3).collect {
39
+ @sensor.read_temperature
40
+ }.inject { |i, s| i + s }
39
41
  total / 3.0
40
42
  end
41
43
  end
42
44
 
43
45
  class TestTemperatureSampler < Test::Unit::TestCase
44
- include FlexMock::TestCase
45
-
46
- def test_temperature_sampler
46
+ def test_sensor_can_average_three_temperature_readings
47
47
  sensor = flexmock("temp")
48
- sensor.should_receive(:read_temperature).times(3).and_return(10, 12, 14)
48
+ sensor.should_receive(:read_temperature).times(3).
49
+ and_return(10, 12, 14)
49
50
 
50
51
  sampler = TemperatureSampler.new(sensor)
51
52
  assert_equal 12, sampler.average_temp
53
+ end
54
+ end
55
+
56
+ You can find an extended example of FlexMock in {Google Example}[http://flexmock.rubyforge.org/files/doc/GoogleExample_rdoc.html].
57
+
58
+ == Test::Unit Integration
59
+
60
+ FlexMock integrates nicely with Test::Unit. Just require the
61
+ 'flexmock/test_unit' file at the top of your test file. The +flexmock+ method
62
+ will be available for mock creation, and any created mocks will be
63
+ automatically validated and closed at the end of the individual test.
64
+
65
+ Your test case will look something like this:
52
66
 
53
- # NOTE:
54
- # all mocks created by the flexmock method will be
55
- # automatically verified during the test teardown.
67
+ require 'flexmock/test_unit'
68
+
69
+ class TestDog < Test::Case::TestCase
70
+ def test_dog_wags
71
+ tail_mock = flexmock(:wag => :happy)
72
+ assert_equal :happy, tail_mock.wag
56
73
  end
57
74
  end
58
75
 
76
+ <b>NOTE:</b> If you don't want to automatically extend every TestCase with the
77
+ flexmock methods and overhead, then require the 'flexmock' file and explicitly
78
+ include the FlexMock::TestCase module in each test case class where you wish
79
+ to use mock objects. FlexMock versions prior to 0.6.0 required the explicit
80
+ include.
81
+
82
+ == RSpec Integration
83
+
84
+ FlexMock also supports integration with the RSpec behavior specification framework. Starting with version 0.9.0 of RSpec, you will be able to say:
85
+
86
+ Spec::Runner.configure do |config|
87
+ config.mock_with :flexmock
88
+ end
89
+
90
+ context "Using FlexMock with RSpec" do
91
+ specify "should be able to create a mock" do
92
+ m = flexmock(:foo => :bar)
93
+ m.foo.should === :bar
94
+ end
95
+ end
96
+
97
+ If you wish to try this prior to the release of RSpec 0.9.0, check out the trunk of the RSpec subversion repository.
98
+
59
99
  == Quick Reference
60
100
 
101
+ === Creating Mock Objects
102
+
103
+ The +flexmock+ method is used to create mocks in various configurations. Here's a quick rundown of the most common options. See FlexMock::MockContainer#flexmock for more details.
104
+
105
+ * <b>m = flexmock("joe")</b>
106
+
107
+ Create a mock object named "joe" (the name is used in reporting errors).
108
+
109
+ * <b>m = flexmock(:foo => :bar, :baz => :froz)</b>
110
+
111
+ Create a mock object and define two mocked methods (:foo and :baz) that
112
+ return the values :bar and :froz respectively. This is useful when creating
113
+ mock objects with just a few methods and simple return values.
114
+
115
+ * <b>m = flexmock("joe", :foo => :bar, :bar => :froz)</b>
116
+
117
+ You can combine the mock name and an expectation hash in the same call to
118
+ flexmock.
119
+
120
+ * <b>m = flexmock(real_object)</b>
121
+
122
+ If you you give +flexmock+ a real object in the argument list, it will treat
123
+ that real object as a base for a partial mock object. The return value +m+
124
+ may be used to set expectations. The real_object should be used in the
125
+ reference portion of the test.
126
+
127
+ * <b>m = flexmock(real_object, "name", :foo => :baz)</b>
128
+
129
+ Names and expectation hashes may be used with partial mocks as well.
130
+
131
+ * <b>m = flexmock(:base, real_string_object)</b>
132
+
133
+ Since Strings (and Symbols for that matter) are used for mock names,
134
+ FlexMock will not recognize them as the base for a partial mock. To force a
135
+ string to be used as a partial mock base, proceed the string object in the
136
+ calling sequence with :base.
137
+
138
+ * <b>m = flexmock(...) { |mock| mock.should_receive(...) }</b>
139
+
140
+ If a block is given to any of the +flexmock+ forms, the mock object will be
141
+ passed to the block as an argument. Code in the block can set the desired
142
+ expectations for the mock object.
143
+
144
+ <b>NOTE:</b> Versions of FlexMock prior to 0.6.0 used +flexstub+ to create partial mocks. The +flexmock+ method now assumes all the functionality that was spread out between two different methods. +flexstub+ is still available for backward compatibility.
145
+
61
146
  === Expectation Declarators
62
147
 
63
- Expectation declarators are used to specify the expectations placed
64
- upon received method calls. The following declarators may be used to
65
- create the proper expectations on a FlexMock object.
66
-
67
- * <b><tt>should_receive(<em>symbol</em>)</tt></b> -- Declares that a
68
- message named <em>symbol</em> will be sent to the mock object.
69
- Further refinements on this expected message (called an expectation)
70
- may be chained to the +should_receive+ call.
71
-
72
- * <b><tt>should_expect</tt></b> -- Creates a mock recording object
73
- that will translate received method calls into mock expectations.
74
- The recorder is passed to a block supplied with the +should_expect+
75
- method. See examples below.
76
-
77
- * <b><tt>with(<em>arglist</em>)</tt></b> -- Declares that this
78
- expectation matches messages that match the given argument list.
79
- The <tt>===</tt> operator is used on a argument by argument basis to
80
- determine matching. This means that most literal values match
81
- literally, class values match any instance of a class and regular
82
- expression match any matching string (after a +to_s+ conversion).
83
- See argument validators (below) for details on argument validation
84
- options.
85
-
86
- * <b><tt>with_any_args</tt></b> -- Declares that this expectation
87
- matches the message with any argument (default)
88
-
89
- * <b><tt>with_no_args</tt></b> -- Declares that this expectation
90
- matches messages with no arguments
91
-
92
- * <b><tt>and_return(<em>value, ...</em>)</tt></b> -- Declares
93
- that the message will return the given value.
94
- * If a single value is given, it will be returned for all matching calls.
95
- * If multiple values are given, they will be returned in sequence
96
- for each successive matching calls. The last value will be
97
- repeatably returned if the number of matching calls exceeds the
98
- number of values.
99
- * If a block is given, its yielded value will be returned. (the
100
- block will receive all the arguments given to the mocked method)
101
- * The default return value is nil.
102
-
103
- * <b><tt>returns(<em>value, ...</em>)</tt></b> -- Alias for
104
- <tt>and_return</tt>.
105
-
106
- * <b><tt>returns { |args| code ... }</tt></b> -- Declares that the
107
- message will return whatever the block calculates. The actual
108
- arguments in the message will be passed to the block.
109
-
110
- * <b><tt>zero_or_more_times</tt></b> -- Declares that the message is
111
- may be sent zero or more times (default, equivalent to
112
- <tt>at_least.never</tt>).
113
-
114
- * <b><tt>once</tt></b> -- Declares that the message is only sent once.
115
- <tt>at_least</tt> / <tt>at_most</tt> modifiers are allowed.
148
+ Once a mock is created, you need to define what that mock should expect to
149
+ see. Expectation declarators are used to specify these expectations placed
150
+ upon received method calls. A basic expectation, created with the
151
+ +should_receive+ method, just establishes the fact that a method may (or may
152
+ not) be called on the mock object. Refinements to that expectation may be
153
+ additionally declared. FlexMock always starts with the most general
154
+ expectation and adds constraints to that.
116
155
 
117
- * <b><tt>twice</tt></b> -- Declares that the message is only sent
118
- twice. <tt>at_least</tt> / <tt>at_most</tt> modifiers are allowed.
156
+ For example, the following code:
119
157
 
120
- * <b><tt>never</tt></b> -- Declares that the message is never sent.
121
- <tt>at_least</tt> / <tt>at_most</tt> modifiers are allowed.
158
+ mock.should_recieve(:average).and_return(12)
159
+
160
+ Means that the mock will now accept method calls to an +average+ method. The
161
+ expectation will accept any arguments and may be called any number of times
162
+ (including zero times). Strictly speaking, the +and_return+ part of the
163
+ declaration isn't exactly a constraint, but it does specify what value the
164
+ mock will return when the expectation is matched.
165
+
166
+ If you want to be more specific, you need to add additional constraints to
167
+ your expectation. Here are some examples:
168
+
169
+ mock.should_receive(:average).with(12).once
170
+
171
+ mock.should_receive(:average).with(Integer).
172
+ at_least.twice.at_most.times(10).
173
+ and_return { rand }
174
+
175
+ The following methods may be used to create and refine expectations on a mock
176
+ object. See theFlexMock::Expectation for more details.
177
+
178
+ * <b>should_receive(<em>method_name</em>)</b>
179
+
180
+ Declares that a message named <em>method_name</em> will be sent to the mock
181
+ object. Constraints on this expected message (called expectations) may be
182
+ chained to the +should_receive+ call.
183
+
184
+ * <b>should_receive(<em>method_name1</em>, <em>method_name2</em>, ...)</b>
185
+
186
+ Define a number of expected messages that have the same constraints.
187
+
188
+ * <b>should_receive(<em>meth1</em> => <em>result1</em>, <em>meth2</em> => <em>result2</em>, ...)</b>
189
+
190
+ Define a number of expected messages that have the same constrants, but
191
+ return different values.
192
+
193
+ * <b>should_expect { |recorder| ... }</b>
194
+
195
+ Creates a mock recording object that will translate received method calls
196
+ into mock expectations. The recorder is passed to a block supplied with the
197
+ +should_expect+ method. See examples below.
198
+
199
+ * <b>with(<em>arglist</em>)</b>
200
+
201
+ Declares that this expectation matches messages that match the given
202
+ argument list. The <tt>===</tt> operator is used on a argument by argument
203
+ basis to determine matching. This means that most literal values match
204
+ literally, class values match any instance of a class and regular expression
205
+ match any matching string (after a +to_s+ conversion). See argument
206
+ validators (below) for details on argument validation options.
207
+
208
+ * <b>with_any_args</b>
209
+
210
+ Declares that this expectation matches the message with any argument
211
+ (default)
212
+
213
+ * <b>with_no_args</b>
214
+
215
+ Declares that this expectation matches messages with no arguments
216
+
217
+ * <b>and_return(<em>value</em>)</b>
218
+
219
+ Declares that the expected message will return the given value.
122
220
 
123
- * <b><tt>times(<em>n</em>)</tt></b> -- Declares that the message is
124
- sent <em>n</em> times. <tt>at_least</tt> / <tt>at_most</tt>
125
- modifiers are allowed.
221
+ * <b>and_return(<em>value1</em>, <em>value2</em>, ...)</b>
126
222
 
127
- * <b><tt>at_least</tt></b> -- Modifies the immediately following
128
- message count declarator so that it means the message is sent at
129
- least that number of times. E.g. <tt>at_least.once</tt> means the
130
- message is sent at least once during the test, but may be sent more
131
- often. Both <tt>at_least</tt> and <tt>at_most</tt> may be specified
132
- on the same expectation.
223
+ Declares that the expected message will return a series of values. Each
224
+ invocation of the message will return the next value in the series. The last
225
+ value will be repeatably returned if the number of matching calls exceeds
226
+ the number of values.
133
227
 
134
- * <b><tt>at_most</tt></b> -- Similar to <tt>at_least</tt>, but puts an
135
- upper limit on the number of messages. Both <tt>at_least</tt> and
228
+ * <b>and_return { |args, ...| code ... } </b>
229
+
230
+ Declares that the expected message will return the yielded value of the
231
+ block. The block will receive all the arguments in the message. If the
232
+ message was provided a block, it will be passed as the last parameter of the
233
+ block's argument list.
234
+
235
+ * <b>returns( ... )</b>
236
+
237
+ Alias for <tt>and_return</tt>.
238
+
239
+ * <b>zero_or_more_times</b>
240
+
241
+ Declares that the expected message is may be sent zero or more times
242
+ (default, equivalent to <tt>at_least.never</tt>).
243
+
244
+ * <b>once</b>
245
+
246
+ Declares that the expected message is only sent once. <tt>at_least</tt> /
247
+ <tt>at_most</tt> modifiers are allowed.
248
+
249
+ * <b>twice</b>
250
+
251
+ Declares that the expected message is only sent twice. <tt>at_least</tt> /
252
+ <tt>at_most</tt> modifiers are allowed.
253
+
254
+ * <b>never</b>
255
+
256
+ Declares that the expected message is never sent. <tt>at_least</tt> /
257
+ <tt>at_most</tt> modifiers are allowed.
258
+
259
+ * <b>times(<em>n</em>)</b>
260
+
261
+ Declares that the expected message is sent <em>n</em> times.
262
+ <tt>at_least</tt> / <tt>at_most</tt> modifiers are allowed.
263
+
264
+ * <b>at_least</b>
265
+
266
+ Modifies the immediately following message count constraint so that it means
267
+ the message is sent at least that number of times. E.g.
268
+ <tt>at_least.once</tt> means the message is sent at least once during the
269
+ test, but may be sent more often. Both <tt>at_least</tt> and
136
270
  <tt>at_most</tt> may be specified on the same expectation.
137
271
 
138
- * <b><tt>ordered</tt></b> -- Declares that the message is ordered and
139
- is expected to be received in a certain position in a sequence of
140
- messages. The message should arrive after and previously declared
141
- ordered messages and prior to any following declared ordered
142
- messages. Unordered messages are ignored when considering the
143
- message order.
144
-
145
- * <b><tt>ordered(<em>group</em>)</tt></b> -- Declare that the given
146
- method belongs to an order group. Methods within the group may be
147
- received in any order. Ordered messages outside the group must be
148
- received either before or after the grouped messages.
149
-
150
- For example, in the following, messages +flip+ and +flop+ may be
151
- received in any order (because they are in the same group), but must
152
- occur strictly after +start+ but before +end+. The message
153
- +any_time+ may be received at any time because it is not ordered.
154
-
155
- m = FlexMock.new
156
- m.should_receive(:any_time)
157
- m.should_receive(:start).ordered
158
- m.should_receive(:flip).ordered(:flip_flop_group)
159
- m.should_receive(:flop).ordered(:flip_flop_group)
160
- m.should_receive(:end).ordered
161
-
272
+ * <b>at_most</b>
273
+
274
+ Similar to <tt>at_least</tt>, but puts an upper limit on the number of
275
+ messages. Both <tt>at_least</tt> and <tt>at_most</tt> may be specified on
276
+ the same expectation.
277
+
278
+ * <b>ordered</b>
279
+
280
+ Declares that the expected message is ordered and is expected to be received
281
+ in a certain position in a sequence of messages. The message should arrive
282
+ after and previously declared ordered messages and prior to any following
283
+ declared ordered messages. Unordered messages are ignored when considering
284
+ the message order.
285
+
286
+ * <b>ordered(<em>group</em>)</b>
287
+
288
+ Declare that the expected message belongs to an order group. Methods within
289
+ an order group may be received in any order. Ordered messages outside the
290
+ group must be received either before or after all of the grouped messages.
291
+
292
+ For example, in the following, messages +flip+ and +flop+ may be received in
293
+ any order (because they are in the same group), but must occur strictly
294
+ after +start+ but before +end+. The message +any_time+ may be received at
295
+ any time because it is not ordered.
296
+
297
+ m = flexmock()
298
+ m.should_receive(:any_time)
299
+ m.should_receive(:start).ordered
300
+ m.should_receive(:flip).ordered(:flip_flop_group)
301
+ m.should_receive(:flop).ordered(:flip_flop_group)
302
+ m.should_receive(:end).ordered
303
+
304
+ * <b>mock</b>
305
+
306
+ Expectation constraints always return the expectation so that the
307
+ constraints can be chained. If you wish to do a one-liner and assign the
308
+ mock to a variable, the +mock+ method on an expectation will return the
309
+ original mock object.
310
+
311
+ m = flexmock.should_receive(:hello).once.and_return("World").mock
312
+
162
313
  === Argument Validation
163
314
 
164
- The values passed to the +with+ declarator determine the criteria for
165
- matching expectations. The first expectation found that matches the
166
- arguments in a mock method call will be used to validate that mock
167
- method call.
315
+ The values passed to the +with+ declarator determine the criteria for matching
316
+ expectations. The first expectation found that matches the arguments in a mock
317
+ method call will be used to validate that mock method call.
168
318
 
169
319
  The following rules are used for argument matching:
170
320
 
171
- * A +with+ parameter that is a class object will match any actual
172
- argument that is an instance of that class.
321
+ * A +with+ parameter that is a class object will match any actual argument
322
+ that is an instance of that class.
173
323
 
174
324
  Examples:
175
325
 
176
326
  with(Integer) will match f(3)
177
327
 
178
- * A regular expression will match any actual argument that matches the
179
- regular expression. Non-string actual arguments are converted to
180
- strings via +to_s+ before applying the regular expression.
328
+ * A regular expression will match any actual argument that matches the regular
329
+ expression. Non-string actual arguments are converted to strings via +to_s+
330
+ before applying the regular expression.
181
331
 
182
332
  Examples:
183
333
 
@@ -190,12 +340,11 @@ The following rules are used for argument matching:
190
340
 
191
341
  with(3) will match f(3)
192
342
  with("hello") will match f("hello")
193
-
194
- * If you wish to override the default matching behavior and force
195
- matching by equality, you can use the FlexMock.eq convenience
196
- method. This is mostly used when you wish to match class objects,
197
- since the default matching behavior for class objects is to match
198
- instances, not themselves.
343
+
344
+ * If you wish to override the default matching behavior and force matching by
345
+ equality, you can use the FlexMock.eq convenience method. This is mostly
346
+ used when you wish to match class objects, since the default matching
347
+ behavior for class objects is to match instances, not themselves.
199
348
 
200
349
  Examples:
201
350
 
@@ -212,8 +361,8 @@ The following rules are used for argument matching:
212
361
  * If you wish to match _anything_, then use the <tt>FlexMock.any</tt>
213
362
  method in the with argument list.
214
363
 
215
- Examples (assumes either the FlexMock::TestCase or
216
- FlexMock::ArgumentTypes mix-ins has been included):
364
+ Examples (assumes either the FlexMock::TestCase or FlexMock::ArgumentTypes
365
+ mix-ins has been included):
217
366
 
218
367
  with(any) will match f(3)
219
368
  with(any) will match f("hello")
@@ -229,15 +378,17 @@ The following rules are used for argument matching:
229
378
 
230
379
  will match any even integer.
231
380
 
232
- === Stubbing Behavior in Existing Objects
381
+ === Creating Partial Mocks
233
382
 
234
383
  Sometimes it is useful to mock the behavior of one or two methods in an
235
- existing object without changing the behavior of the rest of the object. By
236
- using the +flexstub+ method, tests can now do exactly that.
384
+ existing object without changing the behavior of the rest of the object. If
385
+ you pass a real object to the +flexmock+ method, it will allow you to use that
386
+ real object in your test and will just mock out the one or two methods that
387
+ you specify.
237
388
 
238
- For example, suppose that a Dog object uses a Woofer object to
239
- bark. The code for Dog looks like this (we will leave the code for
240
- Woofer to your imagination):
389
+ For example, suppose that a Dog object uses a Woofer object to bark. The code
390
+ for Dog looks like this (we will leave the code for Woofer to your
391
+ imagination):
241
392
 
242
393
  class Dog
243
394
  def initialize
@@ -246,109 +397,136 @@ Woofer to your imagination):
246
397
  def bark
247
398
  @woofer.woof
248
399
  end
400
+ def wag
401
+ :happy
402
+ end
249
403
  end
250
404
 
251
- Now we want to test Dog, but using a real Woofer object in the test is
252
- a real pain (why? ... well because Woofer plays a sound file of a dog
253
- barking, and that's really annoying during testing).
405
+ Now we want to test Dog, but using a real Woofer object in the test is a real
406
+ pain (why? ... well because Woofer plays a sound file of a dog barking, and
407
+ that's really annoying during testing).
254
408
 
255
- So, how can we create a Dog object with mocked Woofer? All we need to
256
- do is stub out the +new+ method of the Woofer class object and tell to
257
- to return anything we want.
409
+ So, how can we create a Dog object with mocked Woofer? All we need to do is
410
+ allow FlexMock to replace the +bark+ method.
258
411
 
259
412
  Here's the test code:
260
413
 
261
414
  class TestDogBarking < Test::Unit::TestCase
262
415
  include FlexMock::TestCase
263
416
 
264
- # Setup the tests by stubbing the +new+ method of
417
+ # Setup the tests by mocking the +new+ method of
265
418
  # Woofer and return a mock woofer.
266
419
  def setup
267
- flexstub(Woofer).should_receive(:new).and_return {
268
- flexmock("woofer") do |mock|
269
- mock.should_receive(:woof).and_return(:grrrr)
270
- end
271
- }
420
+ @dog = Dog.new
421
+ flexmock(dog, :bark => :grrr)
272
422
  end
273
423
 
274
- def test_bark
275
- assert_equal :grrrr, @dog.bark
424
+ def test_dog
425
+ assert_equal :grrrr, @dog.bark # Mocked Method
426
+ assert_equal :happy, @dog.wag # Normal Method
276
427
  end
277
428
  end
278
429
 
279
- The nice thing about stub is that after the test is over, the stubbed
280
- out methods are returned to their normal state. Outside the test
281
- everything is back to normal.
282
-
283
- The stub technique was inspired by the +Stuba+ library in the +Mocha+
284
- project.
285
-
286
- === Stubbing Behavior in All Instances Created by a Class Object
287
-
288
- Sometimes you want to stub all instances created by a class object.
289
- For example, you might wish to work with Connection objects that have
290
- their "send" method stubbed out. However, the code under test creates
291
- connections dynamically, so you can't stub them before the test is
292
- run.
293
-
294
- One approach is to stub the "new" method on the class object. The
295
- stubbed implementation of "new" would create a mock object to be
296
- returned as the value of "new". But since your stubbed implementation
297
- of "new" has no access to the original behavior of new, you can't
298
- really create stubs.
299
-
300
- The <tt>any_instance</tt> method allows you to easily add stub
301
- expectations to objects created by new. Here's the Connection example
302
- using <tt>any_instance</tt>:
303
-
304
- def test_connections
305
- flexstub(Connection).any_instance do |new_con|
306
- new_con.should_receive(:send).and_return(0)
307
- end
308
- connection = Connection.new
309
- connection.send # This calls the stubbed version of send.
310
- end
430
+ The nice thing about this technique is that after the test is over, the mocked
431
+ out methods are returned to their normal state. Outside the test everything is
432
+ back to normal.
311
433
 
312
- Note that FlexMock adds the stub expectations after the original +new+
313
- method has completed. If the original version of +new+ yields the
314
- newly created instance to a block, that block will get an unstubbed
315
- version of the object.
434
+ <b>NOTE:</b> In previous versions of FlexMock, partial mocking was called
435
+ "stubs" and the +flexstub+ method was used to create the partial mocks.
436
+ Although partial mocks were often used as stubs, the terminology was not quite
437
+ correct. The current version of FlexMock uses the +flexmock+ method to create
438
+ both regular stubs and partial stubs. A version of the +flexstub+ method is
439
+ included for backwards compatibility. See Martin Fowler's article <em>Mocks
440
+ Aren't Stubs</em> (http://www.martinfowler.com/articles/mocksArentStubs.html)
441
+ for a better understanding of the difference between mocks and stubs.
316
442
 
317
- === Class Interception
443
+ This partial mocking technique was inspired by the +Stuba+ library in the
444
+ +Mocha+ project.
318
445
 
319
- <b>NOTE:</b> ::
320
- <em>Class Interception is now deprecated. It only worked in a
321
- small number of cases. See the "Mocking Existing Objects"
322
- example above for a much better approach to the same problem.
323
- Version 0.5.x will be the last version of FlexMock that supports the
324
- Class Interception API.</em>
446
+ === Mocking Class Objects
325
447
 
326
- FlexMock now supports simple class interception. For the duration of a test, a
327
- mock class take the place of a named class inside the class to be tested.
448
+ In the previous example we mocked out the +bark+ method of a Dog object to
449
+ avoid invoking the Woofer object. Perhaps a better technique would be to mock
450
+ the Woofer object directly. But Dog uses Woofer explicitly so we cannot just
451
+ pass in a mock object for Dog to use.
328
452
 
329
- Example:
453
+ But wait, we can add mock behavior to any existing object, and classes are
454
+ objects in Ruby. So why don't we just mock out the Woofer class object to
455
+ return mocks for us.
330
456
 
331
- Suppose we are testing class Foo, and Foo uses Bar internally. We
332
- would like for Bar.new to return a mock object during the test.
457
+ class TestDogBarking < Test::Unit::TestCase
458
+ include FlexMock::TestCase
333
459
 
334
- def test_foo_with_an_intercepted_bar
335
- my_mock = flexmock("my_mock").should_receive(....).mock
336
- intercept(Bar).in(Foo).with(my_mock.mock_factory)
460
+ # Setup the tests by mocking the +new+ method of
461
+ # Woofer and return a mock woofer.
462
+ def setup
463
+ flexmock(Woofer).should_receive(:new).
464
+ and_return(flexmock(:woof => :grrr))
465
+ @dog = Dog.new
466
+ end
337
467
 
338
- bar = Bar.new
339
- bar.do_something
340
- end
468
+ def test_dog
469
+ assert_equal :grrrr, @dog.bark # Calls woof on mock object
470
+ # returned by Woofer.new
471
+ end
472
+ end
473
+
474
+ === Mocking Behavior in All Instances Created by a Class Object
475
+
476
+ Sometimes returning a single mock object is not enough. Occasionally you want
477
+ to mock <em>every</em> instance object created by a class. FlexMock makes this
478
+ very easy.
479
+
480
+ class TestDogBarking < Test::Unit::TestCase
481
+ include FlexMock::TestCase
482
+
483
+ # Setup the tests by mocking Woofer to always
484
+ # return partial mocks.
485
+ def setup
486
+ flexmock(Woofer).new_instances.should_receive(:woof => :grrr)
487
+ end
488
+
489
+ def test_dog
490
+ assert_equal :grrrr, Dog.new.bark # All dog objects
491
+ assert_equal :grrrr, Dog.new.bark # are mocked.
492
+ end
493
+ end
494
+
495
+ Note that FlexMock adds the mock expectations after the original +new+ method
496
+ has completed. If the original version of +new+ yields the newly created
497
+ instance to a block, that block will get an non-mocked version of the object.
498
+
499
+ Note that +new_instances+ will accept a block if you wish to mock several
500
+ methods at the same time. E.g.
501
+
502
+ flexmock(Woofer).new_instances do |m|
503
+ m.should_receive(:woof).twice.and_return(:grrr)
504
+ m.should_receive(:wag).at_least.once.and_return(:happy)
505
+ end
341
506
 
342
507
  == Examples
343
508
 
509
+ === Create a simple mock object that returns a value for a set of method calls
510
+
511
+ require 'flexmock/test_unit'
512
+
513
+ class TestSimple < Test::Unit::TestCase
514
+ def test_simple_mock
515
+ m = flexmock(:pi => 3.1416, :e => 2.71)
516
+ assert_equal 3.1416, m.pi
517
+ assert_equal 2.71, m.e
518
+ end
519
+ end
520
+
344
521
  === Expect multiple queries and a single update
345
522
 
346
- The queries my have any arguments. The update must have a specific
347
- argument of 5.
523
+ Multiple calls to the query method will be allows, and calls may have any
524
+ argument list. Each call to query will return the three element array [1, 2,
525
+ 3]. The call to update must have a specific argument of 5.
348
526
 
349
- class TestDb
350
- include FlexMock::TestCase
527
+ require 'flexmock/test_unit'
351
528
 
529
+ class TestDb < Test::Unit::TestCase
352
530
  def test_db
353
531
  db = flexmock('db')
354
532
  db.should_receive(:query).and_return([1,2,3])
@@ -359,8 +537,8 @@ argument of 5.
359
537
 
360
538
  === Expect all queries before any updates
361
539
 
362
- (This and following examples assume that the FlexMock::TestCase module
363
- is being used.)
540
+ (This and following examples assume that the 'flexmock/test_unit' file has
541
+ been required.)
364
542
 
365
543
  All the query message must occur before any of the update messages.
366
544
 
@@ -467,25 +645,28 @@ ignoring.
467
645
  <b>Note:</b> The original +mock_ignore_missing+ is now an alias for
468
646
  +should_ignore_missing+.
469
647
 
470
- == Classic +mock_handle+ Interface
648
+ === Mock just one method on an existing object
471
649
 
472
- FlexMock still supports the simple +mock_handle+ interface used in the
473
- original version of FlexMock. +mock_handle+ is equivalent to the
474
- following:
650
+ The Portfolio class calculate the value of a set of stocks by talking to a quote service via a web service. Since we don't want to use a real web service in our unit tests, we will mock the quote service.
475
651
 
476
- def mock_handle(sym, expected_count=nil, &block)
477
- self.should_receive(sym).times(expected_count).returns(&block)
652
+ def test_portfolio_value
653
+ flexmock(QuoteService).new_instances do |m|
654
+ m.should_receive(:quote).and_return(100)
655
+ end
656
+ port = Portfolio.new
657
+ value = port.value # Portfolio calls QuoteService.quote
658
+ assert_equal 100, value
478
659
  end
479
660
 
480
661
  == Other Mock Objects
481
662
 
482
- ruby-mock :: http://www.b13media.com/dev/ruby/mock.html
483
663
  test-unit-mock :: http://www.deveiate.org/code/Test-Unit-Mock.shtml
484
664
  mocha/stubba :: http://mocha.rubyforge.org/
665
+ Schmock :: http://rubyforge.org/projects/schmock/
485
666
 
486
667
  == License
487
668
 
488
- Copyright 2003, 2004, 2005, 2006 by Jim Weirich (jim@weirichhouse.org).
669
+ Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
489
670
  All rights reserved.
490
671
 
491
672
  Permission is granted for use, copying, modification, distribution,