flexmock 0.5.1 → 0.6.0

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.
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,