flexmock 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|