flexmock 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/README +36 -9
- data/Rakefile +1 -1
- data/lib/flexmock.rb +70 -3
- data/test/test_record_mode.rb +51 -0
- data/test/test_should_receive.rb +19 -0
- metadata +3 -3
data/CHANGELOG
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
= Changes for FlexMock
|
2
2
|
|
3
|
+
== Version 0.2.1
|
4
|
+
|
5
|
+
* Added strict mode in record mode interface to facility using known
|
6
|
+
good algorithms for comparison testing.
|
7
|
+
* Improved the docs and examples. Fixed garbled first example in
|
8
|
+
README.
|
9
|
+
|
3
10
|
== Version 0.2.0
|
4
11
|
|
5
12
|
* Added record mode for building expectations.
|
data/README
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
FlexMock is a simple mock object for unit testing. The interface is
|
4
4
|
simple, but still provides a good bit of flexibility.
|
5
5
|
|
6
|
-
Version :: 0.2.
|
6
|
+
Version :: 0.2.1
|
7
7
|
|
8
8
|
= Links
|
9
9
|
|
@@ -40,10 +40,11 @@ Here's the complete example:
|
|
40
40
|
def test_tempurature_sampler
|
41
41
|
readings = [10, 12, 14]
|
42
42
|
FlexMock.use("temp") do |sensor|
|
43
|
-
sensor = FlexMock.new
|
44
43
|
sensor.should_receive(:read_temperature).and_return { readings.shift }
|
45
|
-
|
46
|
-
|
44
|
+
|
45
|
+
sampler = TemperatureSampler.new(sensor)
|
46
|
+
assert_equal 12, sampler.average_temp
|
47
|
+
end
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
@@ -226,7 +227,7 @@ All the query message must occur before any of the update messages.
|
|
226
227
|
|
227
228
|
FlexMock('db').use |db|
|
228
229
|
db.should_receive(:query).and_return([1,2,3]).ordered
|
229
|
-
db.
|
230
|
+
db.should_recieve(:update).and_return(nil).ordered
|
230
231
|
# test code here
|
231
232
|
end
|
232
233
|
|
@@ -254,19 +255,45 @@ values to figure out what value to return.
|
|
254
255
|
# test code here
|
255
256
|
end
|
256
257
|
|
257
|
-
=== Same as above, but using the
|
258
|
+
=== Same as above, but using the Record Mode interface
|
259
|
+
|
260
|
+
The record mode interface offers much the same features as the
|
261
|
+
+should_receive+ interface introduced so far, but it allows the
|
262
|
+
messages to be sent directly to a recording object rather than be
|
263
|
+
specified indirectly using a symbol.
|
258
264
|
|
259
265
|
FlexMock('db').use |db|
|
260
266
|
db.should_expect do |rec|
|
261
267
|
rec.startup.once.ordered
|
262
268
|
rec.query("CPWR") { 12.3 }.once.ordered(:queries)
|
263
269
|
rec.query("MSFT") { 10.0 }.once.ordered(:queries)
|
264
|
-
rec.query(
|
265
|
-
rec.finish
|
270
|
+
rec.query("^....$/) { 3.3 }.at_least.once.ordered(:queries)
|
271
|
+
rec.finish)once.ordered
|
266
272
|
end
|
267
|
-
# test code here
|
273
|
+
# test code here using +db+.
|
268
274
|
end
|
269
275
|
|
276
|
+
=== Using Record Mode to record a known, good algorithm for testing
|
277
|
+
|
278
|
+
Record mode is nice when you have a known, good algorithm that can use
|
279
|
+
a recording mock object to record the steps. Then you compare the
|
280
|
+
execution of a new algorithm to behavior of the old using the recorded
|
281
|
+
expectations in the mock. For this you probably want to put the
|
282
|
+
recorder in _strict_ mode so that the recorded expectations use exact
|
283
|
+
matching on argument lists, and strict ordering of the method calls.
|
284
|
+
|
285
|
+
<b>Note:</b> This is most useful when there are no queries on the mock
|
286
|
+
objects, because the query responses cannot be programmed into the
|
287
|
+
recorder object.
|
288
|
+
|
289
|
+
FlexMock.use('builder') do |builder|
|
290
|
+
builder.should_expect do |rec|
|
291
|
+
rec.should_be_strict
|
292
|
+
known_good_way_to_build_xml(rec) # record the messages
|
293
|
+
end
|
294
|
+
new_way_to_build_xml(builder) # compare to new way
|
295
|
+
end
|
296
|
+
|
270
297
|
=== Expect multiple calls, returning a different value each time
|
271
298
|
|
272
299
|
Sometimes you need to return different values for each call to a
|
data/Rakefile
CHANGED
data/lib/flexmock.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003, 2004, 2005 by Jim Weirich (jim@weirichhouse.org).
|
4
|
+
# Copyright 2003, 2004, 2005, 2006 by Jim Weirich (jim@weirichhouse.org).
|
5
5
|
# All rights reserved.
|
6
6
|
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -213,8 +213,16 @@ class FlexMock
|
|
213
213
|
end
|
214
214
|
|
215
215
|
# Invoke the expectations for a given set of arguments.
|
216
|
+
#
|
217
|
+
# First, look for an expectation that matches the arguements and
|
218
|
+
# is eligible to be called. Failing that, look for a expectation
|
219
|
+
# that matches teh arguments (at this point it will be ineligible,
|
220
|
+
# but at least we will get a good failure message). Finally,
|
221
|
+
# check for expectations that don't have any argument matching
|
222
|
+
# criteria.
|
216
223
|
def call(*args)
|
217
|
-
exp = @expectations.find { |e| e.match_args(args) } ||
|
224
|
+
exp = @expectations.find { |e| e.match_args(args) && e.eligible? } ||
|
225
|
+
@expectations.find { |e| e.match_args(args) } ||
|
218
226
|
@expectations.find { |e| e.expected_args.nil? }
|
219
227
|
FlexMock.check("no matching handler found for " +
|
220
228
|
FlexMock.format_args(@sym, args)) { ! exp.nil? }
|
@@ -315,6 +323,13 @@ class FlexMock
|
|
315
323
|
@exp = expectation
|
316
324
|
@limit = limit
|
317
325
|
end
|
326
|
+
|
327
|
+
# If the expectation has been called +n+ times, is it still
|
328
|
+
# eligible to be called again? The default answer compares n to
|
329
|
+
# the established limit.
|
330
|
+
def eligible?(n)
|
331
|
+
n < @limit
|
332
|
+
end
|
318
333
|
end
|
319
334
|
|
320
335
|
####################################################################
|
@@ -340,6 +355,14 @@ class FlexMock
|
|
340
355
|
"Method '#{@exp}' should be called at least #{@limit} times,\n" +
|
341
356
|
"only called #{n} times"
|
342
357
|
end
|
358
|
+
|
359
|
+
# If the expectation has been called +n+ times, is it still
|
360
|
+
# eligible to be called again? Since this validator only
|
361
|
+
# establishes a lower limit, not an upper limit, then the answer
|
362
|
+
# is always true.
|
363
|
+
def eligible?(n)
|
364
|
+
true
|
365
|
+
end
|
343
366
|
end
|
344
367
|
|
345
368
|
####################################################################
|
@@ -396,6 +419,12 @@ class FlexMock
|
|
396
419
|
@return_block.call(*args)
|
397
420
|
end
|
398
421
|
|
422
|
+
# Is this expectation eligible to be called again? It is eligible
|
423
|
+
# only if all of its count validators agree that it is eligible.
|
424
|
+
def eligible?
|
425
|
+
@count_validators.all? { |v| v.eligible?(@actual_count) }
|
426
|
+
end
|
427
|
+
|
399
428
|
# Validate that the order
|
400
429
|
def validate_order
|
401
430
|
return if @order_number.nil?
|
@@ -569,15 +598,53 @@ class FlexMock
|
|
569
598
|
# mock object.
|
570
599
|
#
|
571
600
|
class Recorder
|
601
|
+
include FlexMock::ArgumentTypes
|
602
|
+
|
572
603
|
# Create a method recorder for the mock +mock+.
|
573
604
|
def initialize(mock)
|
574
605
|
@mock = mock
|
606
|
+
@strict = false
|
607
|
+
end
|
608
|
+
|
609
|
+
# Place the record in strict mode. While recording expectations
|
610
|
+
# in strict mode, the following will be true.
|
611
|
+
#
|
612
|
+
# * All expectations will be expected in the order they were
|
613
|
+
# recorded.
|
614
|
+
# * All expectations will be expected once.
|
615
|
+
# * All arguments will be placed in exact match mode,
|
616
|
+
# including regular expressions and class objects.
|
617
|
+
#
|
618
|
+
# Strict mode is usually used when giving the recorder to a known
|
619
|
+
# good algorithm. Strict mode captures the exact sequence of
|
620
|
+
# calls and validate that the code under test performs the exact
|
621
|
+
# same sequence of calls.
|
622
|
+
#
|
623
|
+
# The recorder may exit strict mode via a
|
624
|
+
# <tt>should_be_strict(false)</tt> call. Non-strict expectations
|
625
|
+
# may be recorded at that point, or even explicit expectations
|
626
|
+
# (using +should_receieve+) can be specified.
|
627
|
+
#
|
628
|
+
def should_be_strict(is_strict=true)
|
629
|
+
@strict = is_strict
|
630
|
+
end
|
631
|
+
|
632
|
+
# Is the recorder in strict mode?
|
633
|
+
def strict?
|
634
|
+
@strict
|
575
635
|
end
|
576
636
|
|
577
637
|
# Record an expectation for receiving the method +sym+ with the
|
578
638
|
# given arguments.
|
579
639
|
def method_missing(sym, *args, &block)
|
580
|
-
@mock.should_receive(sym).and_return(&block)
|
640
|
+
expectation = @mock.should_receive(sym).and_return(&block)
|
641
|
+
if @strict
|
642
|
+
args = args.collect { |arg| eq(arg) }
|
643
|
+
expectation.with(*args).ordered.once
|
644
|
+
else
|
645
|
+
expectation.with(*args)
|
646
|
+
end
|
647
|
+
expectation
|
581
648
|
end
|
582
649
|
end
|
583
650
|
|
data/test/test_record_mode.rb
CHANGED
@@ -106,4 +106,55 @@ class TestRecordMode < Test::Unit::TestCase
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
+
def test_strict_record_mode_requires_exact_argument_matches
|
110
|
+
assert_fails do
|
111
|
+
FlexMock.use("mock") do |mock|
|
112
|
+
mock.should_expect do |rec|
|
113
|
+
rec.should_be_strict
|
114
|
+
rec.f(Integer)
|
115
|
+
end
|
116
|
+
mock.f(3)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_strict_record_mode_requires_exact_ordering
|
122
|
+
assert_fails do
|
123
|
+
FlexMock.use("mock") do |mock|
|
124
|
+
mock.should_expect do |rec|
|
125
|
+
rec.should_be_strict
|
126
|
+
rec.f(1)
|
127
|
+
rec.f(2)
|
128
|
+
end
|
129
|
+
mock.f(2)
|
130
|
+
mock.f(1)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_strict_record_mode_requires_once
|
136
|
+
assert_fails do
|
137
|
+
FlexMock.use("mock") do |mock|
|
138
|
+
mock.should_expect do |rec|
|
139
|
+
rec.should_be_strict
|
140
|
+
rec.f(1)
|
141
|
+
end
|
142
|
+
mock.f(1)
|
143
|
+
mock.f(1)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_strict_record_mode_can_not_fail
|
149
|
+
FlexMock.use("mock") do |mock|
|
150
|
+
mock.should_expect do |rec|
|
151
|
+
rec.should_be_strict
|
152
|
+
rec.f(Integer)
|
153
|
+
rec.f(2)
|
154
|
+
end
|
155
|
+
mock.f(Integer)
|
156
|
+
mock.f(2)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
109
160
|
end
|
data/test/test_should_receive.rb
CHANGED
@@ -507,6 +507,25 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
507
507
|
assert_equal 'f(1, "two", /^3$/)', exp.to_s
|
508
508
|
end
|
509
509
|
|
510
|
+
def test_explicit_ordering_with_limits_allow_multiple_return_values
|
511
|
+
FlexMock.use('mock') do |m|
|
512
|
+
m.should_receive(:f).with(2).once.and_return { :first_time }
|
513
|
+
m.should_receive(:f).with(2).twice.and_return { :second_or_third_time }
|
514
|
+
m.should_receive(:f).with(2).and_return { :forever }
|
515
|
+
|
516
|
+
assert_equal :first_time, m.f(2)
|
517
|
+
assert_equal :second_or_third_time, m.f(2)
|
518
|
+
assert_equal :second_or_third_time, m.f(2)
|
519
|
+
assert_equal :forever, m.f(2)
|
520
|
+
assert_equal :forever, m.f(2)
|
521
|
+
assert_equal :forever, m.f(2)
|
522
|
+
assert_equal :forever, m.f(2)
|
523
|
+
assert_equal :forever, m.f(2)
|
524
|
+
assert_equal :forever, m.f(2)
|
525
|
+
assert_equal :forever, m.f(2)
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
510
529
|
def assert_failure
|
511
530
|
assert_raises(Test::Unit::AssertionFailedError) do yield end
|
512
531
|
end
|
metadata
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.11.
|
2
|
+
rubygems_version: 0.8.11.5
|
3
3
|
specification_version: 1
|
4
4
|
name: flexmock
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
6
|
+
version: 0.2.1
|
7
7
|
date: 2006-03-21 00:00:00 -05:00
|
8
8
|
summary: Simple and Flexible Mock Objects for Testing
|
9
9
|
require_paths:
|
@@ -32,8 +32,8 @@ files:
|
|
32
32
|
- Rakefile
|
33
33
|
- README
|
34
34
|
- lib/flexmock.rb
|
35
|
-
- test/test_record_mode.rb
|
36
35
|
- test/test_should_receive.rb
|
36
|
+
- test/test_record_mode.rb
|
37
37
|
- test/test_samples.rb
|
38
38
|
- test/test_mock.rb
|
39
39
|
- test/test_naming.rb
|