flexmock 0.2.0 → 0.2.1

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.
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.0
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
- sampler = TemperatureSampler.new(sensor)
46
- assert_equal 12, sampler.average_temp
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.should_receive(:update).and_return(nil).ordered
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 record mode interface
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(/^....$/) { 3.3 }.at_least.once.ordered(:queries)
265
- rec.finish.once.ordered
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
@@ -8,7 +8,7 @@ require 'rake/testtask'
8
8
 
9
9
  CLOBBER.include("html", 'pkg')
10
10
 
11
- PKG_VERSION = '0.2.0'
11
+ PKG_VERSION = '0.2.1'
12
12
 
13
13
  PKG_FILES = FileList[
14
14
  '[A-Z]*',
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).with(*args)
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
 
@@ -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
@@ -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.6
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.0
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