flexmock 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -1
- data/README +390 -209
- data/Rakefile +31 -10
- data/doc/GoogleExample.rdoc +275 -0
- data/doc/releases/flexmock-0.6.0.rdoc +136 -0
- data/lib/flexmock.rb +3 -1160
- data/lib/flexmock/argument_matchers.rb +57 -0
- data/lib/flexmock/argument_types.rb +42 -0
- data/lib/flexmock/base.rb +22 -0
- data/lib/flexmock/composite.rb +10 -0
- data/lib/flexmock/core.rb +206 -0
- data/lib/flexmock/core_class_methods.rb +92 -0
- data/lib/flexmock/default_framework_adapter.rb +31 -0
- data/lib/flexmock/expectation.rb +334 -0
- data/lib/flexmock/expectation_director.rb +59 -0
- data/lib/flexmock/mock_container.rb +159 -0
- data/lib/flexmock/noop.rb +13 -0
- data/lib/flexmock/partial_mock.rb +226 -0
- data/lib/flexmock/recorder.rb +71 -0
- data/lib/flexmock/rspec.rb +34 -0
- data/lib/flexmock/test_unit.rb +32 -0
- data/lib/flexmock/test_unit_integration.rb +53 -0
- data/lib/flexmock/validators.rb +77 -0
- data/test/rspec_integration/integration_spec.rb +36 -0
- data/test/test_container_methods.rb +119 -0
- data/test/test_default_framework_adapter.rb +39 -0
- data/test/test_example.rb +1 -1
- data/test/test_extended_should_receive.rb +63 -0
- data/test/test_mock.rb +1 -1
- data/test/test_naming.rb +1 -1
- data/test/{test_any_instance.rb → test_new_instances.rb} +15 -8
- data/test/{test_stubbing.rb → test_partial_mock.rb} +44 -44
- data/test/test_record_mode.rb +1 -1
- data/test/test_samples.rb +6 -8
- data/test/test_should_receive.rb +7 -3
- data/test/test_tu_integration.rb +1 -1
- data/test/test_unit_integration/test_auto_test_unit.rb +34 -0
- metadata +30 -5
- 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
|
-
==
|
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.
|
6
|
+
Version :: 0.6.0
|
7
7
|
|
8
8
|
= Links
|
9
9
|
|
10
|
-
<b>Documents</b> :: http://
|
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 {
|
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
|
-
|
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).
|
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
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
118
|
-
twice. <tt>at_least</tt> / <tt>at_most</tt> modifiers are allowed.
|
156
|
+
For example, the following code:
|
119
157
|
|
120
|
-
|
121
|
-
|
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
|
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
|
-
|
128
|
-
message
|
129
|
-
|
130
|
-
|
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
|
135
|
-
|
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
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
-
|
166
|
-
|
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
|
-
|
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
|
-
|
180
|
-
|
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
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
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
|
-
===
|
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.
|
236
|
-
|
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
|
-
|
240
|
-
|
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
|
-
|
253
|
-
|
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?
|
256
|
-
|
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
|
417
|
+
# Setup the tests by mocking the +new+ method of
|
265
418
|
# Woofer and return a mock woofer.
|
266
419
|
def setup
|
267
|
-
|
268
|
-
|
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
|
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
|
280
|
-
out methods are returned to their normal state.
|
281
|
-
|
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
|
-
|
313
|
-
|
314
|
-
|
315
|
-
version of the
|
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
|
-
|
443
|
+
This partial mocking technique was inspired by the +Stuba+ library in the
|
444
|
+
+Mocha+ project.
|
318
445
|
|
319
|
-
|
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
|
-
|
327
|
-
|
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
|
-
|
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
|
-
|
332
|
-
|
457
|
+
class TestDogBarking < Test::Unit::TestCase
|
458
|
+
include FlexMock::TestCase
|
333
459
|
|
334
|
-
|
335
|
-
|
336
|
-
|
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
|
-
|
339
|
-
|
340
|
-
|
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
|
-
|
347
|
-
argument
|
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
|
-
|
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
|
363
|
-
|
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
|
-
|
648
|
+
=== Mock just one method on an existing object
|
471
649
|
|
472
|
-
|
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
|
477
|
-
|
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,
|