flexmock 0.5.0 → 0.5.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 +11 -1
- data/README +5 -4
- data/Rakefile +19 -1
- data/doc/releases/flexmock-0.5.1.rdoc +86 -0
- data/lib/flexmock.rb +144 -90
- data/test/test_any_instance.rb +100 -12
- data/test/test_mock.rb +1 -1
- data/test/test_should_receive.rb +132 -74
- data/test/test_stubbing.rb +28 -3
- metadata +4 -2
data/CHANGELOG
CHANGED
@@ -2,13 +2,23 @@
|
|
2
2
|
|
3
3
|
= Changes for FlexMock
|
4
4
|
|
5
|
+
== Pre Version 0.5.1
|
6
|
+
|
7
|
+
* Changed the name of any_instance to new_instances.
|
8
|
+
Deprecated any_instance.
|
9
|
+
* Added ability to stub any class method in new_instances.
|
10
|
+
* Added RCov task
|
11
|
+
* Reworked original behavior hooks to use method aliasing rather than method
|
12
|
+
procs.
|
13
|
+
* Fixed bug in stubbing File class methods.
|
14
|
+
|
5
15
|
== Version 0.5.0
|
6
16
|
|
7
17
|
* Added any_instance stubbing to class objects.
|
8
18
|
|
9
19
|
== Version 0.4.5
|
10
20
|
|
11
|
-
* Fixed version typo in 0.4.4 (
|
21
|
+
* Fixed version typo in 0.4.4 (internally claimed to be 0.4.3.1)
|
12
22
|
|
13
23
|
== Version 0.4.4
|
14
24
|
|
data/README
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
FlexMock is a simple, but flexible, mock object library for Ruby unit
|
4
4
|
testing.
|
5
5
|
|
6
|
-
Version :: 0.5.
|
6
|
+
Version :: 0.5.1
|
7
7
|
|
8
8
|
= Links
|
9
9
|
|
@@ -320,8 +320,8 @@ version of the object.
|
|
320
320
|
<em>Class Interception is now deprecated. It only worked in a
|
321
321
|
small number of cases. See the "Mocking Existing Objects"
|
322
322
|
example above for a much better approach to the same problem.
|
323
|
-
|
324
|
-
|
323
|
+
Version 0.5.x will be the last version of FlexMock that supports the
|
324
|
+
Class Interception API.</em>
|
325
325
|
|
326
326
|
FlexMock now supports simple class interception. For the duration of a test, a
|
327
327
|
mock class take the place of a named class inside the class to be tested.
|
@@ -380,7 +380,7 @@ but the third query (which matches any query call with a four
|
|
380
380
|
character parameter) may be called multiple times (but at least once).
|
381
381
|
Startup and finish must also happen exactly once.
|
382
382
|
|
383
|
-
Also note that we use the +with+ method to match different
|
383
|
+
Also note that we use the +with+ method to match different argument
|
384
384
|
values to figure out what value to return.
|
385
385
|
|
386
386
|
def test_ordered_queries
|
@@ -482,6 +482,7 @@ following:
|
|
482
482
|
ruby-mock :: http://www.b13media.com/dev/ruby/mock.html
|
483
483
|
test-unit-mock :: http://www.deveiate.org/code/Test-Unit-Mock.shtml
|
484
484
|
mocha/stubba :: http://mocha.rubyforge.org/
|
485
|
+
|
485
486
|
== License
|
486
487
|
|
487
488
|
Copyright 2003, 2004, 2005, 2006 by Jim Weirich (jim@weirichhouse.org).
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ require 'rake/testtask'
|
|
9
9
|
CLEAN.include('*.tmp')
|
10
10
|
CLOBBER.include("html", 'pkg')
|
11
11
|
|
12
|
-
PKG_VERSION = '0.5.
|
12
|
+
PKG_VERSION = '0.5.1'
|
13
13
|
|
14
14
|
PKG_FILES = FileList[
|
15
15
|
'[A-Z]*',
|
@@ -29,6 +29,7 @@ RDOC_FILES = FileList[
|
|
29
29
|
|
30
30
|
task :default => [:test_all]
|
31
31
|
task :test_all => [:test]
|
32
|
+
task :test_units => [:test]
|
32
33
|
task :ta => [:test_all]
|
33
34
|
|
34
35
|
# Test Targets -------------------------------------------------------
|
@@ -39,6 +40,23 @@ Rake::TestTask.new do |t|
|
|
39
40
|
t.warning = true
|
40
41
|
end
|
41
42
|
|
43
|
+
Rake::TestTask.new(:test_extended) do |t|
|
44
|
+
t.test_files = FileList['test/extended/test_*.rb']
|
45
|
+
t.verbose = true
|
46
|
+
t.verbose = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# RCov Target --------------------------------------------------------
|
50
|
+
|
51
|
+
require 'rcov/rcovtask'
|
52
|
+
|
53
|
+
Rcov::RcovTask.new do |t|
|
54
|
+
t.libs << "test"
|
55
|
+
t.rcov_opts = ['-xRakefile', '-xrakefile', '-xpublish.rf', '--text-report']
|
56
|
+
t.test_files = FileList['test/test*.rb']
|
57
|
+
t.verbose = true
|
58
|
+
end
|
59
|
+
|
42
60
|
# RDoc Target --------------------------------------------------------
|
43
61
|
|
44
62
|
task :rdoc => ["README"]
|
@@ -0,0 +1,86 @@
|
|
1
|
+
= FlexMock 0.5.0 Released
|
2
|
+
|
3
|
+
FlexMock is a flexible mocking library for use in Ruby's Test::Unit
|
4
|
+
test framework. Version 0.5.1 is a minor bug fix release.
|
5
|
+
|
6
|
+
== New in 0.5.1
|
7
|
+
|
8
|
+
* Version 0.5.1 fixes a problem that caused some older versions of
|
9
|
+
RCov to core dump.
|
10
|
+
|
11
|
+
== What is FlexMock?
|
12
|
+
|
13
|
+
FlexMock is a flexible Ruby mocking library that works with Ruby's
|
14
|
+
Test::Unit framework to create easy to use mocks.
|
15
|
+
|
16
|
+
=== Features
|
17
|
+
|
18
|
+
* Easy integration with Test::Unit. Mocks created with the flexmock
|
19
|
+
method are automatically verified at the end of the test.
|
20
|
+
|
21
|
+
* A fluent interface that allows mock behavior to be specified very
|
22
|
+
easily.
|
23
|
+
|
24
|
+
* A "record mode" where an existing implementation can record its
|
25
|
+
interaction with a mock for later validation against a new
|
26
|
+
implementation.
|
27
|
+
|
28
|
+
* Easy mocking of individual methods in existing, non-mock objects.
|
29
|
+
|
30
|
+
=== Example
|
31
|
+
|
32
|
+
Suppose you had a Dog object that wagged a tail when it was happy.
|
33
|
+
Something like this:
|
34
|
+
|
35
|
+
class Dog
|
36
|
+
def initialize(a_tail)
|
37
|
+
@tail = a_tail
|
38
|
+
end
|
39
|
+
def happy
|
40
|
+
@tail.wag
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
To test the +Dog+ class without a real +Tail+ object (perhaps because
|
45
|
+
real +Tail+ objects activate servos in some robotic equipment), you
|
46
|
+
can do something like this:
|
47
|
+
|
48
|
+
require 'test/unit'
|
49
|
+
require 'flexmock'
|
50
|
+
|
51
|
+
class TestDog < Test::Unit::TestCase
|
52
|
+
include FlexMock::TestCase
|
53
|
+
|
54
|
+
def test_dog_wags_tail_when_happy
|
55
|
+
tail = flexmock("tail")
|
56
|
+
tail.should_receive(:wag).once
|
57
|
+
dog = Dog.new(tail)
|
58
|
+
dog.happy
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
FlexMock will automatically verify that the mocked tail object
|
63
|
+
received the message +wag+ exactly one time. If it doesn't, the test
|
64
|
+
will not pass.
|
65
|
+
|
66
|
+
See the FlexMock documentation at
|
67
|
+
http://onestepback.org/software/flexmock for details on specifying
|
68
|
+
arguments and return values on mocked methods, as well as a simple
|
69
|
+
technique for mocking tail objects when the Dog class creates the tail
|
70
|
+
objects directly.
|
71
|
+
|
72
|
+
== Availability
|
73
|
+
|
74
|
+
You can make sure you have the latest version with a quick RubyGems command:
|
75
|
+
|
76
|
+
gem install flexmock (you may need root/admin privileges)
|
77
|
+
|
78
|
+
Otherwise, you can get it from the more traditional places:
|
79
|
+
|
80
|
+
Download:: http://rubyforge.org/project/showfiles.php?group_id=170
|
81
|
+
|
82
|
+
You will find documentation at:
|
83
|
+
http://onestepback.org/software/flexmock/
|
84
|
+
|
85
|
+
-- Jim Weirich
|
86
|
+
|
data/lib/flexmock.rb
CHANGED
@@ -66,7 +66,7 @@ class FlexMock
|
|
66
66
|
@ignore_missing = false
|
67
67
|
@verified = false
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
# Handle all messages denoted by +sym+ by calling the given block
|
71
71
|
# and passing any parameters to the block. If we know exactly how
|
72
72
|
# many calls are to be made to a particular method, we may check
|
@@ -155,10 +155,14 @@ class FlexMock
|
|
155
155
|
# method_missing. This method defines a singleton method on the
|
156
156
|
# mock to explicitly invoke the method_missing logic.
|
157
157
|
def override_existing_method(sym)
|
158
|
-
sclass.class_eval
|
158
|
+
sclass.class_eval <<-EOS
|
159
|
+
def #{sym}(*args, &block)
|
160
|
+
method_missing(:#{sym}, *args, &block)
|
161
|
+
end
|
162
|
+
EOS
|
159
163
|
end
|
160
164
|
private :override_existing_method
|
161
|
-
|
165
|
+
|
162
166
|
# Return the singleton class of the mock object.
|
163
167
|
def sclass
|
164
168
|
class << self; self; end
|
@@ -208,7 +212,7 @@ class FlexMock
|
|
208
212
|
#
|
209
213
|
# NOTE: If you include FlexMock::TestCase into your test case
|
210
214
|
# file, you can create mocks that will be automatically verified in
|
211
|
-
# the test teardown by using the +flexmock+ method.
|
215
|
+
# the test teardown by using the +flexmock+ method.
|
212
216
|
#
|
213
217
|
def use(*names)
|
214
218
|
names = ["unknown"] if names.empty?
|
@@ -223,7 +227,7 @@ class FlexMock
|
|
223
227
|
mock.mock_verify unless got_exception
|
224
228
|
end
|
225
229
|
end
|
226
|
-
|
230
|
+
|
227
231
|
# Class method to format a method name and argument list as a nice
|
228
232
|
# looking string.
|
229
233
|
def format_args(sym, args)
|
@@ -233,7 +237,7 @@ class FlexMock
|
|
233
237
|
"#{sym}(*args)"
|
234
238
|
end
|
235
239
|
end
|
236
|
-
|
240
|
+
|
237
241
|
# Check will assert the block returns true. If it doesn't, an
|
238
242
|
# assertion failure is triggered with the given message.
|
239
243
|
def check(msg, &block)
|
@@ -248,9 +252,9 @@ class FlexMock
|
|
248
252
|
def mock_wrap(&block)
|
249
253
|
yield
|
250
254
|
rescue Test::Unit::AssertionFailedError => ex
|
251
|
-
raise Test::Unit::AssertionFailedError,
|
252
|
-
|
253
|
-
|
255
|
+
raise Test::Unit::AssertionFailedError,
|
256
|
+
"in mock '#{@mock_name}': #{ex.message}",
|
257
|
+
ex.backtrace
|
254
258
|
end
|
255
259
|
|
256
260
|
####################################################################
|
@@ -297,18 +301,12 @@ class FlexMock
|
|
297
301
|
# criteria.
|
298
302
|
def call(*args)
|
299
303
|
exp = @expectations.find { |e| e.match_args(args) && e.eligible? } ||
|
300
|
-
@expectations.find { |e| e.match_args(args) }
|
301
|
-
@expectations.find { |e| e.expected_args.nil? }
|
304
|
+
@expectations.find { |e| e.match_args(args) }
|
302
305
|
FlexMock.check("no matching handler found for " +
|
303
306
|
FlexMock.format_args(@sym, args)) { ! exp.nil? }
|
304
307
|
exp.verify_call(*args)
|
305
308
|
end
|
306
309
|
|
307
|
-
# Same as call.
|
308
|
-
def [](*args)
|
309
|
-
call(*args)
|
310
|
-
end
|
311
|
-
|
312
310
|
# Append an expectation to this director.
|
313
311
|
def <<(expectation)
|
314
312
|
@expectations << expectation
|
@@ -333,7 +331,7 @@ class FlexMock
|
|
333
331
|
"ANY"
|
334
332
|
end
|
335
333
|
end
|
336
|
-
|
334
|
+
|
337
335
|
####################################################################
|
338
336
|
# Match only things that are equal.
|
339
337
|
class EqualMatcher
|
@@ -347,7 +345,7 @@ class FlexMock
|
|
347
345
|
"==(#{@obj.inspect})"
|
348
346
|
end
|
349
347
|
end
|
350
|
-
|
348
|
+
|
351
349
|
ANY = AnyMatcher.new
|
352
350
|
|
353
351
|
####################################################################
|
@@ -415,8 +413,8 @@ class FlexMock
|
|
415
413
|
# Validate that the method expectation was called exactly +n+
|
416
414
|
# times.
|
417
415
|
def validate(n)
|
418
|
-
assert_equal @limit, n,
|
419
|
-
|
416
|
+
assert_equal @limit, n,
|
417
|
+
"method '#{@exp}' called incorrect number of times"
|
420
418
|
end
|
421
419
|
end
|
422
420
|
|
@@ -428,8 +426,8 @@ class FlexMock
|
|
428
426
|
# times.
|
429
427
|
def validate(n)
|
430
428
|
assert n >= @limit,
|
431
|
-
|
432
|
-
|
429
|
+
"Method '#{@exp}' should be called at least #{@limit} times,\n" +
|
430
|
+
"only called #{n} times"
|
433
431
|
end
|
434
432
|
|
435
433
|
# If the expectation has been called +n+ times, is it still
|
@@ -448,8 +446,8 @@ class FlexMock
|
|
448
446
|
# Validate the method expectation was called at least +n+ times.
|
449
447
|
def validate(n)
|
450
448
|
assert n <= @limit,
|
451
|
-
|
452
|
-
|
449
|
+
"Method '#{@exp}' should be called at most #{@limit} times,\n" +
|
450
|
+
"only called #{n} times"
|
453
451
|
end
|
454
452
|
end
|
455
453
|
|
@@ -501,11 +499,11 @@ class FlexMock
|
|
501
499
|
@count_validators.all? { |v| v.eligible?(@actual_count) }
|
502
500
|
end
|
503
501
|
|
504
|
-
# Validate that the order
|
502
|
+
# Validate that the order
|
505
503
|
def validate_order
|
506
504
|
return if @order_number.nil?
|
507
505
|
FlexMock.check("method #{to_s} called out of order " +
|
508
|
-
|
506
|
+
"(expected order #{@order_number}, was #{@mock.mock_current_order})") {
|
509
507
|
@order_number >= @mock.mock_current_order
|
510
508
|
}
|
511
509
|
@mock.mock_current_order = @order_number
|
@@ -523,7 +521,9 @@ class FlexMock
|
|
523
521
|
# Does the argument list match this expectation's argument
|
524
522
|
# specification.
|
525
523
|
def match_args(args)
|
526
|
-
|
524
|
+
# TODO: Rethink this:
|
525
|
+
# return false if @expected_args.nil?
|
526
|
+
return true if @expected_args.nil?
|
527
527
|
return false if args.size != @expected_args.size
|
528
528
|
(0...args.size).all? { |i| match_arg(@expected_args[i], args[i]) }
|
529
529
|
end
|
@@ -531,8 +531,8 @@ class FlexMock
|
|
531
531
|
# Does the expected argument match the corresponding actual value.
|
532
532
|
def match_arg(expected, actual)
|
533
533
|
expected === actual ||
|
534
|
-
|
535
|
-
|
534
|
+
expected == actual ||
|
535
|
+
( Regexp === expected && expected === actual.to_s )
|
536
536
|
end
|
537
537
|
|
538
538
|
# Declare that the method should expect the given argument list.
|
@@ -558,15 +558,15 @@ class FlexMock
|
|
558
558
|
#
|
559
559
|
# * If a single value is given, it will be returned for all matching
|
560
560
|
# calls.
|
561
|
-
# * If multiple values are given, each value will be returned in turn for
|
561
|
+
# * If multiple values are given, each value will be returned in turn for
|
562
562
|
# each successive call. If the number of matching calls is greater
|
563
|
-
# than the number of values, the last value will be returned for
|
563
|
+
# than the number of values, the last value will be returned for
|
564
564
|
# the extra matching calls.
|
565
|
-
# * If a block is given, it is evaluated on each call and its
|
566
|
-
# value is returned.
|
567
|
-
#
|
565
|
+
# * If a block is given, it is evaluated on each call and its
|
566
|
+
# value is returned.
|
567
|
+
#
|
568
568
|
# For example:
|
569
|
-
#
|
569
|
+
#
|
570
570
|
# mock.should_receive(:f).returns(12) # returns 12
|
571
571
|
#
|
572
572
|
# mock.should_receive(:f).with(String). # returns an
|
@@ -575,9 +575,12 @@ class FlexMock
|
|
575
575
|
# +and_return+ is an alias for +returns+.
|
576
576
|
#
|
577
577
|
def returns(*args, &block)
|
578
|
-
@return_block =
|
579
|
-
|
580
|
-
|
578
|
+
@return_block =
|
579
|
+
if block_given?
|
580
|
+
block
|
581
|
+
else
|
582
|
+
lambda { args.size == 1 ? args.first : args.shift }
|
583
|
+
end
|
581
584
|
self
|
582
585
|
end
|
583
586
|
alias :and_return :returns # :nodoc:
|
@@ -725,7 +728,7 @@ class FlexMock
|
|
725
728
|
# given arguments.
|
726
729
|
def method_missing(sym, *args, &block)
|
727
730
|
expectation = @mock.should_receive(sym).and_return(&block)
|
728
|
-
if
|
731
|
+
if strict?
|
729
732
|
args = args.collect { |arg| eq(arg) }
|
730
733
|
expectation.with(*args).ordered.once
|
731
734
|
else
|
@@ -734,7 +737,7 @@ class FlexMock
|
|
734
737
|
expectation
|
735
738
|
end
|
736
739
|
end
|
737
|
-
|
740
|
+
|
738
741
|
####################################################################
|
739
742
|
# Test::Unit::TestCase Integration.
|
740
743
|
#
|
@@ -757,7 +760,7 @@ class FlexMock
|
|
757
760
|
super
|
758
761
|
flexmock_teardown
|
759
762
|
end
|
760
|
-
|
763
|
+
|
761
764
|
# Do the flexmock specific teardown stuff.
|
762
765
|
def flexmock_teardown
|
763
766
|
@flexmock_created_mocks ||= []
|
@@ -770,6 +773,7 @@ class FlexMock
|
|
770
773
|
@flexmock_created_mocks.each do |m|
|
771
774
|
m.mock_teardown
|
772
775
|
end
|
776
|
+
@flexmock_created_mocks = []
|
773
777
|
@flexmock_interceptors ||= []
|
774
778
|
@flexmock_interceptors.each do |i|
|
775
779
|
i.restore
|
@@ -788,10 +792,10 @@ class FlexMock
|
|
788
792
|
flexmock_remember(mock)
|
789
793
|
mock
|
790
794
|
end
|
791
|
-
|
795
|
+
|
792
796
|
# Stub the given object by overriding the behavior of individual
|
793
797
|
# methods. The stub object returned will respond to the
|
794
|
-
# +should_receive+ method, just like normal stubs.
|
798
|
+
# +should_receive+ method, just like normal stubs.
|
795
799
|
#
|
796
800
|
# If a block is given, then the stub object is passed to the block
|
797
801
|
# and may be configured within the block.
|
@@ -815,7 +819,7 @@ class FlexMock
|
|
815
819
|
yield(proxy) if block_given?
|
816
820
|
flexmock_remember(proxy)
|
817
821
|
end
|
818
|
-
|
822
|
+
|
819
823
|
# Intercept the named class in the target class for the duration
|
820
824
|
# of the test. Class interception is very simple-minded and has a
|
821
825
|
# number of restrictions. First, the intercepted class must be
|
@@ -838,9 +842,9 @@ class FlexMock
|
|
838
842
|
@flexmock_interceptors << result
|
839
843
|
result
|
840
844
|
end
|
841
|
-
|
845
|
+
|
842
846
|
private
|
843
|
-
|
847
|
+
|
844
848
|
def flexmock_remember(mocking_object)
|
845
849
|
@flexmock_created_mocks ||= []
|
846
850
|
@flexmock_created_mocks << mocking_object
|
@@ -868,11 +872,12 @@ class FlexMock
|
|
868
872
|
|
869
873
|
# Intercept this class in the class to be tested.
|
870
874
|
def intercept(intercepted_class)
|
875
|
+
self.class.show_intercept_warning
|
871
876
|
@intercepted = intercepted_class
|
872
877
|
update
|
873
878
|
self
|
874
879
|
end
|
875
|
-
|
880
|
+
|
876
881
|
# Define the class number test that will receive the
|
877
882
|
# interceptioned definition.
|
878
883
|
def in(target_class)
|
@@ -893,16 +898,16 @@ class FlexMock
|
|
893
898
|
def restore
|
894
899
|
@proxy.proxied_class = @restore_class if @proxy
|
895
900
|
end
|
896
|
-
|
901
|
+
|
897
902
|
private
|
898
|
-
|
903
|
+
|
899
904
|
# Update the interception if the definition is complete.
|
900
905
|
def update
|
901
906
|
if complete?
|
902
907
|
do_interception
|
903
908
|
end
|
904
909
|
end
|
905
|
-
|
910
|
+
|
906
911
|
# Is the interception definition complete. In other words, are
|
907
912
|
# all three actors defined?
|
908
913
|
def complete?
|
@@ -949,6 +954,17 @@ class FlexMock
|
|
949
954
|
raise BadInterceptionError, "in #{where} class #{name}"
|
950
955
|
end
|
951
956
|
end
|
957
|
+
|
958
|
+
@shown_warning = false
|
959
|
+
|
960
|
+
class << self
|
961
|
+
def show_intercept_warning
|
962
|
+
unless @shown_warning
|
963
|
+
@shown_warning = true
|
964
|
+
$stderr.puts "FlexMock Class Interception is deprecated and will be removed in future versions."
|
965
|
+
end
|
966
|
+
end
|
967
|
+
end
|
952
968
|
end
|
953
969
|
|
954
970
|
####################################################################
|
@@ -964,21 +980,21 @@ class FlexMock
|
|
964
980
|
@proxied_class.__send__(sym, *args, &block)
|
965
981
|
end
|
966
982
|
end
|
967
|
-
|
983
|
+
|
968
984
|
####################################################################
|
969
985
|
# StubProxy is used to mate the mock framework to an existing
|
970
986
|
# object. The object is "enhanced" with a reference to a mock
|
971
|
-
# object (stored in <tt>@flexmock_mock</tt>). When the
|
972
|
-
# +should_receive+ method is sent to the proxy, it overrides the
|
973
|
-
# existing object's method by creating singleton method that
|
987
|
+
# object (stored in <tt>@flexmock_mock</tt>). When the
|
988
|
+
# +should_receive+ method is sent to the proxy, it overrides the
|
989
|
+
# existing object's method by creating singleton method that
|
974
990
|
# forwards to the mock. When testing is complete, StubProxy
|
975
|
-
# will erase the mocking infrastructure from the object being
|
976
|
-
# stubbed (e.g. remove instance variables and mock singleton
|
991
|
+
# will erase the mocking infrastructure from the object being
|
992
|
+
# stubbed (e.g. remove instance variables and mock singleton
|
977
993
|
# methods).
|
978
994
|
#
|
979
995
|
class StubProxy
|
980
996
|
attr_reader :mock
|
981
|
-
|
997
|
+
|
982
998
|
# Initialize a StubProxy object.
|
983
999
|
def initialize(obj, mock)
|
984
1000
|
@obj = obj
|
@@ -986,8 +1002,8 @@ class FlexMock
|
|
986
1002
|
@method_definitions = {}
|
987
1003
|
@methods_proxied = []
|
988
1004
|
end
|
989
|
-
|
990
|
-
# Stub out the given method in the existing object and then let the
|
1005
|
+
|
1006
|
+
# Stub out the given method in the existing object and then let the
|
991
1007
|
# mock object handle should_receive.
|
992
1008
|
def should_receive(method_name)
|
993
1009
|
method_name = method_name.to_sym
|
@@ -997,34 +1013,52 @@ class FlexMock
|
|
997
1013
|
end
|
998
1014
|
@mock.should_receive(method_name)
|
999
1015
|
end
|
1000
|
-
|
1001
|
-
#
|
1002
|
-
#
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1016
|
+
|
1017
|
+
# new_instances is a short cut method for overriding the behavior of any
|
1018
|
+
# new instances created via a stubbed class object.
|
1019
|
+
#
|
1020
|
+
# By default, new_instances will stub the behaviour of the :new and
|
1021
|
+
# :allocate methods. If you wish to stub a different set of class
|
1022
|
+
# methods, just pass a list of symbols to as arguments.
|
1023
|
+
#
|
1024
|
+
# For example, to stub only objects created by :make (and not :new
|
1025
|
+
# or :allocate), use:
|
1026
|
+
#
|
1027
|
+
# flexstub(ClassName).new_instances(:make) do |obj|
|
1028
|
+
# obj.should_receive(...)
|
1029
|
+
# end
|
1030
|
+
#
|
1031
|
+
def new_instances(*allocators, &block)
|
1032
|
+
fail ArgumentError, "new_instances requires a Class to stub" unless Class === @obj
|
1033
|
+
fail ArgumentError, "new_instances requires a block" unless block_given?
|
1034
|
+
allocators = [:new, :allocate] if allocators.empty?
|
1035
|
+
allocators.each do |m|
|
1036
|
+
self.should_receive(m).and_return { |*args|
|
1037
|
+
new_obj = invoke_original(m, args)
|
1038
|
+
mock = mock_container.flexstub(new_obj)
|
1039
|
+
block.call(mock)
|
1040
|
+
new_obj
|
1041
|
+
}
|
1042
|
+
end
|
1011
1043
|
nil
|
1012
1044
|
end
|
1013
1045
|
|
1014
|
-
#
|
1046
|
+
# any_instance is present for backwards compatibility with version 0.5.0.
|
1047
|
+
# @deprecated
|
1048
|
+
def any_instance(&block)
|
1049
|
+
$stderr.puts "any_instance is deprecated, use new_instances instead."
|
1050
|
+
new_instances(&block)
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
# Invoke the original definition of method on the object supported by
|
1015
1054
|
# the stub.
|
1016
1055
|
def invoke_original(method, args)
|
1017
|
-
method_proc = @method_definitions[
|
1018
|
-
|
1019
|
-
if Proc === args.last
|
1020
|
-
block = args.last
|
1021
|
-
args = args[0...-1]
|
1022
|
-
end
|
1023
|
-
method_proc.call(*args, &block)
|
1056
|
+
method_proc = @method_definitions[method]
|
1057
|
+
method_proc.call(*args)
|
1024
1058
|
end
|
1025
1059
|
private :invoke_original
|
1026
1060
|
|
1027
|
-
# Verify that the mock has been properly called. After verification,
|
1061
|
+
# Verify that the mock has been properly called. After verification,
|
1028
1062
|
# detach the mocking infrastructure from the existing object.
|
1029
1063
|
def mock_verify
|
1030
1064
|
@mock.mock_verify
|
@@ -1041,14 +1075,14 @@ class FlexMock
|
|
1041
1075
|
@obj = nil
|
1042
1076
|
end
|
1043
1077
|
end
|
1044
|
-
|
1045
|
-
# Return the container for this mocking object. Returns nil if the
|
1078
|
+
|
1079
|
+
# Return the container for this mocking object. Returns nil if the
|
1046
1080
|
# mock is not in a container. Mock containers make sure that mock objects
|
1047
1081
|
# inside the container are torn down at the end of a test
|
1048
1082
|
def mock_container
|
1049
1083
|
@mock.mock_container
|
1050
1084
|
end
|
1051
|
-
|
1085
|
+
|
1052
1086
|
# Set the container for this mock object.
|
1053
1087
|
def mock_container=(container)
|
1054
1088
|
@mock.mock_container = container
|
@@ -1074,7 +1108,23 @@ class FlexMock
|
|
1074
1108
|
# not a singleton, all we need to do is override it with our own
|
1075
1109
|
# singleton.
|
1076
1110
|
def hide_existing_method(method_name)
|
1077
|
-
|
1111
|
+
if @obj.respond_to?(method_name)
|
1112
|
+
new_alias = new_name(method_name)
|
1113
|
+
unless @obj.respond_to?(new_alias)
|
1114
|
+
sclass.class_eval do
|
1115
|
+
alias_method(new_alias, method_name)
|
1116
|
+
end
|
1117
|
+
end
|
1118
|
+
my_object = @obj
|
1119
|
+
@method_definitions[method_name] = Proc.new { |*args|
|
1120
|
+
block = nil
|
1121
|
+
if Proc === args.last
|
1122
|
+
block = args.last
|
1123
|
+
args = args[0...-1]
|
1124
|
+
end
|
1125
|
+
my_object.send(new_alias, *args, &block)
|
1126
|
+
}
|
1127
|
+
end
|
1078
1128
|
remove_current_method(method_name) if singleton?(method_name)
|
1079
1129
|
define_proxy_method(method_name)
|
1080
1130
|
end
|
@@ -1084,9 +1134,7 @@ class FlexMock
|
|
1084
1134
|
# being mocked.
|
1085
1135
|
def define_proxy_method(method_name)
|
1086
1136
|
sclass.class_eval %{
|
1087
|
-
def #{method_name}(*args, &block)
|
1088
|
-
@flexmock_proxy.mock.#{method_name}(*args, &block)
|
1089
|
-
end
|
1137
|
+
def #{method_name}(*args, &block) @flexmock_proxy.mock.#{method_name}(*args, &block) end
|
1090
1138
|
}
|
1091
1139
|
end
|
1092
1140
|
|
@@ -1095,9 +1143,10 @@ class FlexMock
|
|
1095
1143
|
def restore_original_definition(method_name)
|
1096
1144
|
method_def = @method_definitions[method_name]
|
1097
1145
|
if method_def
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1146
|
+
the_alias = new_name(method_name)
|
1147
|
+
sclass.class_eval do
|
1148
|
+
alias_method(method_name, the_alias)
|
1149
|
+
end
|
1101
1150
|
end
|
1102
1151
|
end
|
1103
1152
|
|
@@ -1111,6 +1160,11 @@ class FlexMock
|
|
1111
1160
|
def detached?
|
1112
1161
|
@obj.nil?
|
1113
1162
|
end
|
1114
|
-
|
1163
|
+
|
1164
|
+
# Generate a name to be used to alias the original behavior.
|
1165
|
+
def new_name(old_name)
|
1166
|
+
"flexmock_original_behavior_for_#{old_name}"
|
1167
|
+
end
|
1168
|
+
|
1115
1169
|
end
|
1116
1170
|
end
|
data/test/test_any_instance.rb
CHANGED
@@ -22,6 +22,9 @@ class TestStubbingOnNew < Test::Unit::TestCase
|
|
22
22
|
def wag
|
23
23
|
:tail
|
24
24
|
end
|
25
|
+
def self.make
|
26
|
+
new
|
27
|
+
end
|
25
28
|
end
|
26
29
|
|
27
30
|
class Cat
|
@@ -43,25 +46,42 @@ class TestStubbingOnNew < Test::Unit::TestCase
|
|
43
46
|
:unstubbed
|
44
47
|
end
|
45
48
|
end
|
49
|
+
|
50
|
+
def test_new_instances_requires_block
|
51
|
+
ex = assert_raise(ArgumentError) {
|
52
|
+
flexstub(Dog).new_instances
|
53
|
+
}
|
54
|
+
end
|
46
55
|
|
47
|
-
def
|
48
|
-
flexstub(Dog).
|
56
|
+
def test_new_instances_allows_stubbing_of_existing_methods
|
57
|
+
flexstub(Dog).new_instances do |obj|
|
49
58
|
obj.should_receive(:bark).and_return(:whimper)
|
50
59
|
end
|
51
60
|
m = Dog.new
|
52
61
|
assert_equal :whimper, m.bark
|
53
62
|
end
|
54
63
|
|
55
|
-
def
|
56
|
-
|
64
|
+
def test_any_instance_still_works_for_backwards_compatibility
|
65
|
+
message = redirect_error {
|
66
|
+
flexstub(Dog).any_instance do |obj|
|
67
|
+
obj.should_receive(:bark).and_return(:whimper)
|
68
|
+
assert_match(/deprecated/, message)
|
69
|
+
end
|
70
|
+
}
|
71
|
+
m = Dog.new
|
72
|
+
assert_equal :whimper, m.bark
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_new_instances_stubs_still_have_existing_methods
|
76
|
+
flexstub(Dog).new_instances do |obj|
|
57
77
|
obj.should_receive(:bark).and_return(:whimper)
|
58
78
|
end
|
59
79
|
m = Dog.new
|
60
80
|
assert_equal :tail, m.wag
|
61
81
|
end
|
62
82
|
|
63
|
-
def
|
64
|
-
flexstub(Cat).
|
83
|
+
def test_new_instances_will_pass_args_to_new
|
84
|
+
flexstub(Cat).new_instances do |obj|
|
65
85
|
obj.should_receive(:meow).and_return(:scratch)
|
66
86
|
end
|
67
87
|
x = :not_called
|
@@ -71,8 +91,23 @@ class TestStubbingOnNew < Test::Unit::TestCase
|
|
71
91
|
assert_equal :called, x
|
72
92
|
end
|
73
93
|
|
74
|
-
|
75
|
-
|
94
|
+
# Some versions of the software had problems invoking the block after a
|
95
|
+
# second stubbing.
|
96
|
+
def test_new_gets_block_after_restubbing
|
97
|
+
flexstub(Cat).new_instances { }
|
98
|
+
x = :not_called
|
99
|
+
m = Cat.new("Fido") { x = :called }
|
100
|
+
assert_equal :called, x
|
101
|
+
flexmock_teardown
|
102
|
+
|
103
|
+
flexstub(Cat).new_instances { }
|
104
|
+
x = :not_called
|
105
|
+
m = Cat.new("Fido") { x = :called }
|
106
|
+
assert_equal :called, x
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_new_instances_stub_verification_happens_on_teardown
|
110
|
+
flexstub(Dog).new_instances do |obj|
|
76
111
|
obj.should_receive(:bark).once.and_return(nil)
|
77
112
|
end
|
78
113
|
|
@@ -81,14 +116,54 @@ class TestStubbingOnNew < Test::Unit::TestCase
|
|
81
116
|
assert_match(/method 'bark\(.*\)' called incorrect number of times/, ex.message)
|
82
117
|
end
|
83
118
|
|
84
|
-
def
|
119
|
+
def test_new_instances_reports_error_on_non_classes
|
85
120
|
ex = assert_raise(ArgumentError) {
|
86
|
-
flexstub(Dog.new).
|
121
|
+
flexstub(Dog.new).new_instances do |obj|
|
87
122
|
obj.should_receive(:hi)
|
88
123
|
end
|
89
124
|
}
|
90
125
|
assert_match(/Class/, ex.message)
|
91
|
-
assert_match(/
|
126
|
+
assert_match(/new_instances/, ex.message)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_can_stub_objects_created_with_allocate_instead_of_new
|
130
|
+
flexstub(Dog).new_instances do |obj|
|
131
|
+
obj.should_receive(:bark).and_return(:whimper)
|
132
|
+
end
|
133
|
+
m = Dog.allocate
|
134
|
+
assert_equal :whimper, m.bark
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_can_stub_objects_created_with_arbitrary_class_methods
|
138
|
+
flexstub(Dog).new_instances(:make) do |obj|
|
139
|
+
obj.should_receive(:bark).and_return(:whimper)
|
140
|
+
end
|
141
|
+
assert_equal :whimper, Dog.make.bark
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_stubbing_arbitrary_class_methods_leaves_new_alone
|
145
|
+
flexstub(Dog).new_instances(:make) do |obj|
|
146
|
+
obj.should_receive(:bark).and_return(:whimper)
|
147
|
+
end
|
148
|
+
assert_equal :woof, Dog.new.bark
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_stubbing_new_and_allocate_doesnt_double_stub_objects_on_new
|
152
|
+
counter = 0
|
153
|
+
flexstub(Dog).new_instances do |obj|
|
154
|
+
counter += 1
|
155
|
+
end
|
156
|
+
Dog.new
|
157
|
+
assert_equal 1, counter
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_stubbing_new_and_allocate_doesnt_double_stub_objects_on_allocate
|
161
|
+
counter = 0
|
162
|
+
flexstub(Dog).new_instances do |obj|
|
163
|
+
counter += 1
|
164
|
+
end
|
165
|
+
Dog.allocate
|
166
|
+
assert_equal 1, counter
|
92
167
|
end
|
93
168
|
|
94
169
|
# Current behavior does not install stubs into the block passed to new.
|
@@ -96,7 +171,7 @@ class TestStubbingOnNew < Test::Unit::TestCase
|
|
96
171
|
# moment, we assure that they are not stubbed, but I am willing to change
|
97
172
|
# this in the future.
|
98
173
|
def test_blocks_on_new_do_not_have_stubs_installed
|
99
|
-
flexstub(Connection).
|
174
|
+
flexstub(Connection).new_instances do |new_con|
|
100
175
|
new_con.should_receive(:post).and_return {
|
101
176
|
:stubbed
|
102
177
|
}
|
@@ -108,4 +183,17 @@ class TestStubbingOnNew < Test::Unit::TestCase
|
|
108
183
|
end
|
109
184
|
assert block_run
|
110
185
|
end
|
186
|
+
|
187
|
+
def redirect_error
|
188
|
+
require 'stringio'
|
189
|
+
old_err = $stderr
|
190
|
+
$stderr = StringIO.new
|
191
|
+
yield
|
192
|
+
$stderr.string
|
193
|
+
rescue
|
194
|
+
$stderr = old_err
|
195
|
+
end
|
196
|
+
private :redirect_error
|
111
197
|
end
|
198
|
+
|
199
|
+
|
data/test/test_mock.rb
CHANGED
data/test/test_should_receive.rb
CHANGED
@@ -25,6 +25,13 @@ end
|
|
25
25
|
|
26
26
|
class TestFlexMockShoulds < Test::Unit::TestCase
|
27
27
|
|
28
|
+
# Expected error messages on failures
|
29
|
+
COUNT_ERROR_MESSAGE = /\bcalled\s+incorrect\s+number\s+of\s+times\b/
|
30
|
+
NO_MATCH_ERROR_MESSAGE = /\bno\s+matching\s+handler\b/
|
31
|
+
AT_LEAST_ERROR_MESSAGE = /\bshould\s+be\s+called\s+at\s+least\b/
|
32
|
+
AT_MOST_ERROR_MESSAGE = /\bshould\s+be\s+called\s+at\s+most\b/
|
33
|
+
OUT_OF_ORDER_ERROR_MESSAGE = /\bcalled\s+out\s+of\s+order\b/
|
34
|
+
|
28
35
|
def test_defaults
|
29
36
|
FlexMock.use do |m|
|
30
37
|
m.should_receive(:hi)
|
@@ -87,10 +94,10 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
87
94
|
end
|
88
95
|
|
89
96
|
def test__with_no_args_but_with_args
|
90
|
-
ex = assert_failure do
|
97
|
+
ex = assert_failure(NO_MATCH_ERROR_MESSAGE) do
|
91
98
|
FlexMock.use do |m|
|
92
|
-
|
93
|
-
|
99
|
+
m.should_receive(:hi).with_no_args
|
100
|
+
m.hi(1)
|
94
101
|
end
|
95
102
|
end
|
96
103
|
end
|
@@ -187,8 +194,8 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
187
194
|
def test_arg_matching_with_no_match
|
188
195
|
FlexMock.use do |m|
|
189
196
|
m.should_receive(:hi).with(1).returns(10)
|
190
|
-
assert_failure {
|
191
|
-
|
197
|
+
assert_failure(NO_MATCH_ERROR_MESSAGE) {
|
198
|
+
assert_equal 20, m.hi(2)
|
192
199
|
}
|
193
200
|
end
|
194
201
|
end
|
@@ -196,8 +203,8 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
196
203
|
def test_arg_matching_with_string_doesnt_over_match
|
197
204
|
FlexMock.use do |m|
|
198
205
|
m.should_receive(:hi).with(String).returns(20)
|
199
|
-
assert_failure {
|
200
|
-
|
206
|
+
assert_failure(NO_MATCH_ERROR_MESSAGE) {
|
207
|
+
m.hi(1.0)
|
201
208
|
}
|
202
209
|
end
|
203
210
|
end
|
@@ -205,8 +212,8 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
205
212
|
def test_block_arg_given_to_no_args
|
206
213
|
FlexMock.use do |m|
|
207
214
|
m.should_receive(:hi).with_no_args.returns(20)
|
208
|
-
assert_failure {
|
209
|
-
|
215
|
+
assert_failure(NO_MATCH_ERROR_MESSAGE) {
|
216
|
+
m.hi { 1 }
|
210
217
|
}
|
211
218
|
end
|
212
219
|
end
|
@@ -245,10 +252,10 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
245
252
|
end
|
246
253
|
|
247
254
|
def test_never_and_called_once
|
248
|
-
ex = assert_failure do
|
255
|
+
ex = assert_failure(COUNT_ERROR_MESSAGE) do
|
249
256
|
FlexMock.use do |m|
|
250
|
-
|
251
|
-
|
257
|
+
m.should_receive(:hi).with(1).never
|
258
|
+
m.hi(1)
|
252
259
|
end
|
253
260
|
end
|
254
261
|
end
|
@@ -261,19 +268,19 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
261
268
|
end
|
262
269
|
|
263
270
|
def test_once_but_never_called
|
264
|
-
ex = assert_failure do
|
271
|
+
ex = assert_failure(COUNT_ERROR_MESSAGE) do
|
265
272
|
FlexMock.use do |m|
|
266
|
-
|
273
|
+
m.should_receive(:hi).with(1).returns(10).once
|
267
274
|
end
|
268
275
|
end
|
269
276
|
end
|
270
277
|
|
271
278
|
def test_once_but_called_twice
|
272
|
-
ex = assert_failure do
|
279
|
+
ex = assert_failure(COUNT_ERROR_MESSAGE) do
|
273
280
|
FlexMock.use do |m|
|
274
|
-
|
275
|
-
|
276
|
-
|
281
|
+
m.should_receive(:hi).with(1).returns(10).once
|
282
|
+
m.hi(1)
|
283
|
+
m.hi(1)
|
277
284
|
end
|
278
285
|
end
|
279
286
|
end
|
@@ -321,9 +328,9 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
321
328
|
end
|
322
329
|
|
323
330
|
def test_at_least_but_never_called
|
324
|
-
ex = assert_failure do
|
331
|
+
ex = assert_failure(AT_LEAST_ERROR_MESSAGE) do
|
325
332
|
FlexMock.use do |m|
|
326
|
-
|
333
|
+
m.should_receive(:hi).with(1).returns(10).at_least.once
|
327
334
|
end
|
328
335
|
end
|
329
336
|
end
|
@@ -337,11 +344,11 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
337
344
|
end
|
338
345
|
|
339
346
|
def test_at_least_and_exact
|
340
|
-
ex = assert_failure do
|
347
|
+
ex = assert_failure(COUNT_ERROR_MESSAGE) do
|
341
348
|
FlexMock.use do |m|
|
342
|
-
|
343
|
-
|
344
|
-
|
349
|
+
m.should_receive(:hi).with(1).returns(10).at_least.once.once
|
350
|
+
m.hi(1)
|
351
|
+
m.hi(1)
|
345
352
|
end
|
346
353
|
end
|
347
354
|
end
|
@@ -360,19 +367,19 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
360
367
|
end
|
361
368
|
|
362
369
|
def test_at_most_called_twice
|
363
|
-
ex = assert_failure do
|
370
|
+
ex = assert_failure(AT_MOST_ERROR_MESSAGE) do
|
364
371
|
FlexMock.use do |m|
|
365
|
-
|
366
|
-
|
367
|
-
|
372
|
+
m.should_receive(:hi).with(1).returns(10).at_most.once
|
373
|
+
m.hi(1)
|
374
|
+
m.hi(1)
|
368
375
|
end
|
369
376
|
end
|
370
377
|
end
|
371
378
|
|
372
379
|
def test_at_most_and_at_least_called_never
|
373
|
-
ex = assert_failure do
|
380
|
+
ex = assert_failure(AT_LEAST_ERROR_MESSAGE) do
|
374
381
|
FlexMock.use do |m|
|
375
|
-
|
382
|
+
m.should_receive(:hi).with(1).returns(10).at_least.once.at_most.twice
|
376
383
|
end
|
377
384
|
end
|
378
385
|
end
|
@@ -393,12 +400,12 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
393
400
|
end
|
394
401
|
|
395
402
|
def test_at_most_and_at_least_called_three_times
|
396
|
-
ex = assert_failure do
|
403
|
+
ex = assert_failure(AT_MOST_ERROR_MESSAGE) do
|
397
404
|
FlexMock.use do |m|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
405
|
+
m.should_receive(:hi).with(1).returns(10).at_least.once.at_most.twice
|
406
|
+
m.hi(1)
|
407
|
+
m.hi(1)
|
408
|
+
m.hi(1)
|
402
409
|
end
|
403
410
|
end
|
404
411
|
end
|
@@ -416,18 +423,19 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
416
423
|
end
|
417
424
|
|
418
425
|
def test_call_counts_only_apply_to_matching_args_with_mismatch
|
419
|
-
ex = assert_failure do
|
426
|
+
ex = assert_failure(COUNT_ERROR_MESSAGE) do
|
420
427
|
FlexMock.use do |m|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
428
|
+
m.should_receive(:hi).with(1).once
|
429
|
+
m.should_receive(:hi).with(2).twice
|
430
|
+
m.should_receive(:hi).with(3)
|
431
|
+
m.should_receive(:lo)
|
432
|
+
m.hi(1)
|
433
|
+
m.hi(2)
|
434
|
+
m.lo
|
435
|
+
20.times { m.hi(3) }
|
429
436
|
end
|
430
437
|
end
|
438
|
+
assert_match(/hi\(2\)/, ex.message)
|
431
439
|
end
|
432
440
|
|
433
441
|
def test_ordered_calls_in_order
|
@@ -441,13 +449,13 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
441
449
|
end
|
442
450
|
|
443
451
|
def test_ordered_calls_out_of_order
|
444
|
-
ex = assert_failure do
|
452
|
+
ex = assert_failure(OUT_OF_ORDER_ERROR_MESSAGE) do
|
445
453
|
FlexMock.use 'm' do |m|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
454
|
+
m.should_receive(:hi).ordered
|
455
|
+
m.should_receive(:lo).ordered
|
456
|
+
|
457
|
+
m.lo
|
458
|
+
m.hi
|
451
459
|
end
|
452
460
|
end
|
453
461
|
end
|
@@ -463,13 +471,13 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
463
471
|
end
|
464
472
|
|
465
473
|
def test_order_calls_with_different_arg_lists_and_out_of_order
|
466
|
-
ex = assert_failure do
|
474
|
+
ex = assert_failure(OUT_OF_ORDER_ERROR_MESSAGE) do
|
467
475
|
FlexMock.use 'm' do |m|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
476
|
+
m.should_receive(:hi).with("one").ordered
|
477
|
+
m.should_receive(:hi).with("two").ordered
|
478
|
+
|
479
|
+
m.hi("two")
|
480
|
+
m.hi("one")
|
473
481
|
end
|
474
482
|
end
|
475
483
|
end
|
@@ -500,11 +508,11 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
500
508
|
end
|
501
509
|
end
|
502
510
|
|
503
|
-
def
|
511
|
+
def test_grouped_ordering_with_numbers
|
504
512
|
FlexMock.use 'm' do |m|
|
505
|
-
m.should_receive(:start).ordered(
|
506
|
-
m.should_receive(:flip).ordered(
|
507
|
-
m.should_receive(:flop).ordered(
|
513
|
+
m.should_receive(:start).ordered(1)
|
514
|
+
m.should_receive(:flip).ordered(2)
|
515
|
+
m.should_receive(:flop).ordered(2)
|
508
516
|
m.should_receive(:final).ordered
|
509
517
|
|
510
518
|
m.start
|
@@ -517,9 +525,9 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
517
525
|
|
518
526
|
def test_grouped_ordering_with_symbols
|
519
527
|
FlexMock.use 'm' do |m|
|
520
|
-
m.should_receive(:start).ordered(:
|
521
|
-
m.should_receive(:flip).ordered(:
|
522
|
-
m.should_receive(:flop).ordered(:
|
528
|
+
m.should_receive(:start).ordered(:start_group)
|
529
|
+
m.should_receive(:flip).ordered(:flip_flop_group)
|
530
|
+
m.should_receive(:flop).ordered(:flip_flop_group)
|
523
531
|
m.should_receive(:final).ordered
|
524
532
|
|
525
533
|
m.start
|
@@ -541,17 +549,44 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
541
549
|
end
|
542
550
|
|
543
551
|
def test_explicit_ordering_with_explicit_misorders
|
544
|
-
assert_failure do
|
552
|
+
ex = assert_failure(OUT_OF_ORDER_ERROR_MESSAGE) do
|
545
553
|
FlexMock.use 'm' do |m|
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
554
|
+
m.should_receive(:hi).ordered(:first_group)
|
555
|
+
m.should_receive(:lo).ordered(:second_group)
|
556
|
+
|
557
|
+
m.lo
|
558
|
+
m.hi
|
551
559
|
end
|
552
560
|
end
|
561
|
+
# TODO: It would be nice to get the group names in the error message.
|
562
|
+
# assert_match /first_group/, ex.message
|
563
|
+
# assert_match /second_group/, ex.message
|
553
564
|
end
|
554
|
-
|
565
|
+
|
566
|
+
# Test submitted by Mikael Pahmp to correct expectation matching.
|
567
|
+
def test_ordering_with_explicit_no_args_matches_correctly
|
568
|
+
FlexMock.use("m") do |m|
|
569
|
+
m.should_receive(:foo).with_no_args.once.ordered
|
570
|
+
m.should_receive(:bar).with_no_args.once.ordered
|
571
|
+
m.should_receive(:foo).with_no_args.once.ordered
|
572
|
+
m.foo
|
573
|
+
m.bar
|
574
|
+
m.foo
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
# Test submitted by Mikael Pahmp to correct expectation matching.
|
579
|
+
def test_ordering_with_any_arg_matching_correctly_matches
|
580
|
+
FlexMock.use("m") do |m|
|
581
|
+
m.should_receive(:foo).with_any_args.once.ordered
|
582
|
+
m.should_receive(:bar).with_any_args.once.ordered
|
583
|
+
m.should_receive(:foo).with_any_args.once.ordered
|
584
|
+
m.foo
|
585
|
+
m.bar
|
586
|
+
m.foo
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
555
590
|
def test_expectation_formating
|
556
591
|
m = FlexMock.new("m")
|
557
592
|
exp = m.should_receive(:f).with(1,"two", /^3$/).and_return(0).at_least.once
|
@@ -597,18 +632,41 @@ class TestFlexMockShoulds < Test::Unit::TestCase
|
|
597
632
|
assert_equal :mkf, m2.mock_kernel_function
|
598
633
|
end
|
599
634
|
|
600
|
-
|
601
|
-
|
635
|
+
# Assertion helper used to assert validation failure. If a
|
636
|
+
# message is given, then the error message should match the
|
637
|
+
# expected error message.
|
638
|
+
def assert_failure(message=nil)
|
639
|
+
ex = assert_raises(Test::Unit::AssertionFailedError) { yield }
|
640
|
+
if message
|
641
|
+
case message
|
642
|
+
when Regexp
|
643
|
+
assert_match message, ex.message
|
644
|
+
when String
|
645
|
+
assert ex.message.index(message), "Error message '#{ex.message}' should contain '#{message}'"
|
646
|
+
end
|
647
|
+
end
|
648
|
+
ex
|
602
649
|
end
|
603
|
-
|
604
650
|
end
|
605
651
|
|
606
652
|
class TestFlexMockShouldsWithInclude < Test::Unit::TestCase
|
607
653
|
include FlexMock::ArgumentTypes
|
608
|
-
def
|
654
|
+
def test_include_enables_unqualified_arg_type_references
|
609
655
|
FlexMock.use("x") do |m|
|
610
656
|
m.should_receive(:hi).with(any).once
|
611
657
|
m.hi(1)
|
612
658
|
end
|
613
659
|
end
|
614
660
|
end
|
661
|
+
|
662
|
+
class TestFlexMockArgTypesDontLeak < Test::Unit::TestCase
|
663
|
+
def test_unqualified_arg_type_references_are_undefined_by_default
|
664
|
+
ex = assert_raise(NameError) do
|
665
|
+
FlexMock.use("x") do |m|
|
666
|
+
m.should_receive(:hi).with(any).once
|
667
|
+
m.hi(1)
|
668
|
+
end
|
669
|
+
end
|
670
|
+
assert_match(/\bany\b/, ex.message, "Error message should mention 'any'")
|
671
|
+
end
|
672
|
+
end
|
data/test/test_stubbing.rb
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
#+++
|
11
11
|
|
12
12
|
require 'test/unit'
|
13
|
+
require 'fileutils'
|
13
14
|
require 'flexmock'
|
14
15
|
|
15
16
|
class TestStubbing < Test::Unit::TestCase
|
@@ -127,11 +128,35 @@ class TestStubbing < Test::Unit::TestCase
|
|
127
128
|
end
|
128
129
|
|
129
130
|
def test_original_behavior_is_restored_on_nonsingleton_methods_with_multiple_stubs
|
130
|
-
flexstub(
|
131
|
-
flexstub(
|
131
|
+
flexstub(Dir).should_receive(:chdir).with("xx").once.and_return(:ok1)
|
132
|
+
flexstub(Dir).should_receive(:chdir).with("yy").once.and_return(:ok2)
|
133
|
+
assert_equal :ok1, Dir.chdir("xx")
|
134
|
+
assert_equal :ok2, Dir.chdir("yy")
|
135
|
+
|
136
|
+
flexstub(Dir).mock_teardown
|
137
|
+
|
138
|
+
x = :not_called
|
139
|
+
Dir.chdir("test") do
|
140
|
+
assert_match %r{/test$}, Dir.pwd
|
141
|
+
x = :called
|
142
|
+
end
|
143
|
+
assert_equal :called, x
|
144
|
+
end
|
132
145
|
|
146
|
+
def test_stubbing_file_shouldnt_break_writing
|
147
|
+
flexstub(File).should_receive(:open).with("foo").once.and_return(:ok)
|
133
148
|
assert_equal :ok, File.open("foo")
|
134
|
-
|
149
|
+
flexstub(File).mock_teardown
|
150
|
+
|
151
|
+
File.open("dummy.txt", "w") do |out|
|
152
|
+
assert out.is_a?(IO)
|
153
|
+
out.puts "XYZ"
|
154
|
+
end
|
155
|
+
text = nil
|
156
|
+
File.open("dummy.txt") { |f| text = f.read }
|
157
|
+
assert_equal "XYZ\n", text
|
158
|
+
ensure
|
159
|
+
FileUtils.rm_f("dummy.txt")
|
135
160
|
end
|
136
161
|
|
137
162
|
def test_original_behavior_is_restored_even_when_errors
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: flexmock
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.5.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.5.1
|
7
|
+
date: 2007-04-09 00:00:00 -04:00
|
8
8
|
summary: Simple and Flexible Mock Objects for Testing
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- doc/releases/flexmock-0.4.2.rdoc
|
51
51
|
- doc/releases/flexmock-0.4.3.rdoc
|
52
52
|
- doc/releases/flexmock-0.5.0.rdoc
|
53
|
+
- doc/releases/flexmock-0.5.1.rdoc
|
53
54
|
test_files: []
|
54
55
|
|
55
56
|
rdoc_options:
|
@@ -66,6 +67,7 @@ extra_rdoc_files:
|
|
66
67
|
- doc/releases/flexmock-0.4.2.rdoc
|
67
68
|
- doc/releases/flexmock-0.4.3.rdoc
|
68
69
|
- doc/releases/flexmock-0.5.0.rdoc
|
70
|
+
- doc/releases/flexmock-0.5.1.rdoc
|
69
71
|
executables: []
|
70
72
|
|
71
73
|
extensions: []
|