flexmock 0.9.0 → 1.0.0.beta.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/README.rdoc +325 -177
- data/Rakefile +22 -8
- data/TAGS +772 -669
- data/doc/releases/flexmock-1.0.0.rdoc +128 -0
- data/lib/flexmock.rb +1 -1
- data/lib/flexmock/argument_matchers.rb +16 -3
- data/lib/flexmock/argument_matching.rb +33 -0
- data/lib/flexmock/argument_types.rb +5 -1
- data/lib/flexmock/base.rb +1 -1
- data/lib/flexmock/composite.rb +3 -3
- data/lib/flexmock/core.rb +32 -2
- data/lib/flexmock/core_class_methods.rb +1 -1
- data/lib/flexmock/default_framework_adapter.rb +1 -1
- data/lib/flexmock/deprecated_methods.rb +1 -1
- data/lib/flexmock/errors.rb +1 -1
- data/lib/flexmock/expectation.rb +15 -13
- data/lib/flexmock/expectation_director.rb +1 -1
- data/lib/flexmock/explicit_needed.rb +39 -0
- data/lib/flexmock/mock_container.rb +8 -2
- data/lib/flexmock/noop.rb +1 -1
- data/lib/flexmock/ordering.rb +1 -1
- data/lib/flexmock/partial_mock.rb +12 -2
- data/lib/flexmock/rails.rb +1 -1
- data/lib/flexmock/recorder.rb +1 -1
- data/lib/flexmock/rspec.rb +5 -1
- data/lib/flexmock/rspec_spy_matcher.rb +74 -0
- data/lib/flexmock/spy_describers.rb +60 -0
- data/lib/flexmock/test_unit.rb +1 -1
- data/lib/flexmock/test_unit_assert_spy_called.rb +34 -0
- data/lib/flexmock/test_unit_integration.rb +3 -1
- data/lib/flexmock/undefined.rb +1 -1
- data/lib/flexmock/validators.rb +1 -1
- data/lib/flexmock/version.rb +4 -2
- data/test/assert_spy_called_test.rb +89 -0
- data/test/container_methods_test.rb +1 -1
- data/test/default_framework_adapter_test.rb +1 -1
- data/test/deprecated_methods_test.rb +1 -1
- data/test/examples_from_readme_test.rb +1 -1
- data/test/extended_should_receive_test.rb +1 -1
- data/test/naming_test.rb +1 -2
- data/test/new_instances_test.rb +1 -3
- data/test/partial_mock_test.rb +7 -1
- data/test/record_mode_test.rb +1 -1
- data/test/rspec_integration/integration_spec.rb +11 -3
- data/test/rspec_integration/spy_example_spec.rb +141 -0
- data/test/samples_test.rb +1 -1
- data/test/should_ignore_missing_test.rb +6 -2
- data/test/should_receive_test.rb +31 -2
- data/test/spys_test.rb +148 -0
- data/test/test_unit_integration/auto_test_unit_test.rb +1 -1
- data/test/tu_integration_test.rb +1 -1
- data/test/undefined_test.rb +1 -1
- metadata +16 -8
@@ -0,0 +1,128 @@
|
|
1
|
+
= FlexMock 1.0.0 Released
|
2
|
+
|
3
|
+
FlexMock is a flexible mocking library for use in unit testing and
|
4
|
+
behavior specification in Ruby. Release 1.0.0 is a minor release with
|
5
|
+
a few bug fixes.
|
6
|
+
|
7
|
+
== Changes in 1.0.0
|
8
|
+
|
9
|
+
* Mocks may now have a base class that limits what methods may be
|
10
|
+
mocked. This allows early detection of outdated mock setups when the
|
11
|
+
methods in the class are refactored.
|
12
|
+
|
13
|
+
* Spy assertions are now allowed. The verification of the calling of
|
14
|
+
mocked methods may now be done in the "then" portion of the test,
|
15
|
+
after the code under test has been run. This allows for much more
|
16
|
+
natural Given/When/Then style testing.
|
17
|
+
|
18
|
+
* A custom assert method (assert_spy_called) has been added to make
|
19
|
+
spy assertions easy when using Test::Unit or MiniTest.
|
20
|
+
|
21
|
+
* An RSpec matcher (have_received) has been added to make spy
|
22
|
+
assertions easy when using RSpec.
|
23
|
+
|
24
|
+
== What is FlexMock?
|
25
|
+
|
26
|
+
FlexMock is a flexible framework for creating mock object for testing. When
|
27
|
+
running unit tests, it is often desirable to use isolate the objects being
|
28
|
+
tested from the "real world" by having them interact with simplified test
|
29
|
+
objects. Sometimes these test objects simply return values when called, other
|
30
|
+
times they verify that certain methods were called with particular arguments
|
31
|
+
in a particular order.
|
32
|
+
|
33
|
+
FlexMock makes creating these test objects easy.
|
34
|
+
|
35
|
+
=== Features
|
36
|
+
|
37
|
+
* Easy integration with both Test::Unit and RSpec. Mocks created with the
|
38
|
+
flexmock method are automatically verified at the end of the test or
|
39
|
+
example.
|
40
|
+
|
41
|
+
* A fluent interface that allows mock behavior to be specified very
|
42
|
+
easily.
|
43
|
+
|
44
|
+
* A "record mode" where an existing implementation can record its
|
45
|
+
interaction with a mock for later validation against a new
|
46
|
+
implementation.
|
47
|
+
|
48
|
+
* Easy mocking of individual methods in existing, non-mock objects.
|
49
|
+
|
50
|
+
* Easy mocking of chains of method calls.
|
51
|
+
|
52
|
+
* The ability to cause classes to instantiate test instances (instead of real
|
53
|
+
instances) for the duration of a test.
|
54
|
+
|
55
|
+
=== Example
|
56
|
+
|
57
|
+
Suppose you had a Dog object that wagged a tail when it was happy.
|
58
|
+
Something like this:
|
59
|
+
|
60
|
+
class Dog
|
61
|
+
def initialize(a_tail)
|
62
|
+
@tail = a_tail
|
63
|
+
end
|
64
|
+
def happy
|
65
|
+
@tail.wag
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
To test the +Dog+ class without a real +Tail+ object (perhaps because
|
70
|
+
real +Tail+ objects activate servos in some robotic equipment), you
|
71
|
+
can do something like this:
|
72
|
+
|
73
|
+
RSpec.configure do |config|
|
74
|
+
config.mock_with :flexmock
|
75
|
+
end
|
76
|
+
|
77
|
+
describe Dog do
|
78
|
+
it "wags its tail when happy" do
|
79
|
+
tail = flexmock("tail")
|
80
|
+
tail.should_receive(:wag).once
|
81
|
+
dog = Dog.new(tail)
|
82
|
+
dog.happy
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
FlexMock will automatically verify that the mocked tail object received the
|
87
|
+
message +wag+ exactly one time. If it doesn't, the test will not pass.
|
88
|
+
|
89
|
+
Here's the same thing using the new spy support:
|
90
|
+
|
91
|
+
describe Dog do
|
92
|
+
it "wags its tail when happy" do
|
93
|
+
tail = flexmock("tail")
|
94
|
+
dog = Dog.new(tail)
|
95
|
+
dog.happy
|
96
|
+
tail.should have_received(:wag)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
This style works particularly well with the rspec-given library.
|
101
|
+
|
102
|
+
require 'rspec/given'
|
103
|
+
|
104
|
+
describe Dog do
|
105
|
+
context "when the dog is happy" do
|
106
|
+
Given(:tail) { flexmock(:on, Tail) }
|
107
|
+
Given(:dog) { Dog.new(tail) }
|
108
|
+
|
109
|
+
When { dog.happy }
|
110
|
+
|
111
|
+
Then { tail.should have_received(:wag) }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
See the FlexMock documentation at http://flexmock.rubyforge.org for details on
|
116
|
+
specifying arguments and return values on mocked methods, as well as a simple
|
117
|
+
technique for mocking tail objects when the Dog class creates the tail objects
|
118
|
+
directly.
|
119
|
+
|
120
|
+
== Availability
|
121
|
+
|
122
|
+
You can make sure you have the latest version with a quick RubyGems command:
|
123
|
+
|
124
|
+
gem install flexmock (you may need root/admin privileges)
|
125
|
+
|
126
|
+
You will find documentation at: http://flexmock.rubyforge.org.
|
127
|
+
|
128
|
+
-- Jim Weirich
|
data/lib/flexmock.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
#
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -54,7 +54,7 @@ class FlexMock
|
|
54
54
|
end
|
55
55
|
|
56
56
|
####################################################################
|
57
|
-
# Match
|
57
|
+
# Match hashes that match all the fields of +hash+.
|
58
58
|
class HashMatcher
|
59
59
|
def initialize(hash)
|
60
60
|
@hash = hash
|
@@ -68,7 +68,7 @@ class FlexMock
|
|
68
68
|
end
|
69
69
|
|
70
70
|
####################################################################
|
71
|
-
# Match
|
71
|
+
# Match objects that implement all the methods in +methods+.
|
72
72
|
class DuckMatcher
|
73
73
|
def initialize(methods)
|
74
74
|
@methods = methods
|
@@ -81,5 +81,18 @@ class FlexMock
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
####################################################################
|
85
|
+
# Match objects that implement all the methods in +methods+.
|
86
|
+
class OptionalProcMatcher
|
87
|
+
def initialize
|
88
|
+
end
|
89
|
+
def ===(target)
|
90
|
+
ArgumentMatching.missing?(target) || Proc === target
|
91
|
+
end
|
92
|
+
def inspect
|
93
|
+
"optional_proc"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
OPTIONAL_PROC_MATCHER = OptionalProcMatcher.new
|
84
97
|
|
85
98
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class FlexMock
|
2
|
+
module ArgumentMatching
|
3
|
+
module_function
|
4
|
+
|
5
|
+
MISSING_ARG = Object.new
|
6
|
+
|
7
|
+
def all_match?(expected_args, actual_args)
|
8
|
+
return true if expected_args.nil?
|
9
|
+
return false if actual_args.size > expected_args.size
|
10
|
+
i = 0
|
11
|
+
while i < actual_args.size
|
12
|
+
return false unless match?(expected_args[i], actual_args[i])
|
13
|
+
i += 1
|
14
|
+
end
|
15
|
+
while i < expected_args.size
|
16
|
+
return false unless match?(expected_args[i], MISSING_ARG)
|
17
|
+
i += 1
|
18
|
+
end
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
# Does the expected argument match the corresponding actual value.
|
23
|
+
def match?(expected, actual)
|
24
|
+
expected === actual ||
|
25
|
+
expected == actual ||
|
26
|
+
( Regexp === expected && expected === actual.to_s )
|
27
|
+
end
|
28
|
+
|
29
|
+
def missing?(arg)
|
30
|
+
arg == MISSING_ARG
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -48,6 +48,10 @@ class FlexMock
|
|
48
48
|
def ducktype(*methods)
|
49
49
|
DuckMatcher.new(methods)
|
50
50
|
end
|
51
|
+
|
52
|
+
def optional_proc
|
53
|
+
OPTIONAL_PROC_MATCHER
|
54
|
+
end
|
51
55
|
end
|
52
56
|
extend ArgumentTypes
|
53
57
|
|
data/lib/flexmock/base.rb
CHANGED
data/lib/flexmock/composite.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
|
4
|
+
# All rights reserved.
|
5
5
|
|
6
6
|
require 'flexmock/noop'
|
7
7
|
|
8
8
|
class FlexMock
|
9
9
|
|
10
|
-
end
|
10
|
+
end
|
data/lib/flexmock/core.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
#
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -12,6 +12,8 @@
|
|
12
12
|
require 'flexmock/errors'
|
13
13
|
require 'flexmock/composite'
|
14
14
|
require 'flexmock/ordering'
|
15
|
+
require 'flexmock/argument_matching'
|
16
|
+
require 'flexmock/explicit_needed'
|
15
17
|
|
16
18
|
######################################################################
|
17
19
|
# FlexMock is a flexible mock object framework for supporting testing.
|
@@ -57,6 +59,8 @@ class FlexMock
|
|
57
59
|
@expectations = Hash.new
|
58
60
|
@ignore_missing = false
|
59
61
|
@verified = false
|
62
|
+
@calls = []
|
63
|
+
@base_class = nil
|
60
64
|
container = UseContainer.new if container.nil?
|
61
65
|
container.flexmock_remember(self)
|
62
66
|
end
|
@@ -85,6 +89,7 @@ class FlexMock
|
|
85
89
|
# Ignore all undefined (missing) method calls.
|
86
90
|
def should_ignore_missing
|
87
91
|
@ignore_missing = true
|
92
|
+
self
|
88
93
|
end
|
89
94
|
alias mock_ignore_missing should_ignore_missing
|
90
95
|
|
@@ -95,10 +100,13 @@ class FlexMock
|
|
95
100
|
|
96
101
|
# Handle missing methods by attempting to look up a handler.
|
97
102
|
def method_missing(sym, *args, &block)
|
103
|
+
@calls << [sym, block_given? ? args + [block] : args]
|
98
104
|
flexmock_wrap do
|
99
105
|
if handler = @expectations[sym]
|
100
106
|
args << block if block_given?
|
101
107
|
handler.call(*args)
|
108
|
+
elsif @base_class && @base_class.instance_methods.include?(sym)
|
109
|
+
FlexMock.undefined
|
102
110
|
elsif @ignore_missing
|
103
111
|
FlexMock.undefined
|
104
112
|
else
|
@@ -126,6 +134,27 @@ class FlexMock
|
|
126
134
|
@expectations[method_name]
|
127
135
|
end
|
128
136
|
|
137
|
+
def flexmock_spies_on(base_class)
|
138
|
+
@base_class = base_class
|
139
|
+
end
|
140
|
+
|
141
|
+
def flexmock_was_called_with?(sym, args, options={})
|
142
|
+
count = 0
|
143
|
+
@calls.each { |call_sym, call_args, call_block|
|
144
|
+
count += 1 if (call_sym == sym) && ArgumentMatching.all_match?(args, call_args)
|
145
|
+
}
|
146
|
+
if options[:times]
|
147
|
+
result = count == options[:times]
|
148
|
+
else
|
149
|
+
result = count > 0
|
150
|
+
end
|
151
|
+
result
|
152
|
+
end
|
153
|
+
|
154
|
+
def flexmock_invoke_original(sym, args)
|
155
|
+
return FlexMock.undefined
|
156
|
+
end
|
157
|
+
|
129
158
|
# Override the built-in +method+ to include the mocked methods.
|
130
159
|
def method(sym)
|
131
160
|
@expectations[sym] || super
|
@@ -162,9 +191,10 @@ class FlexMock
|
|
162
191
|
result = Expectation.new(self, sym)
|
163
192
|
@expectations[sym] << result
|
164
193
|
override_existing_method(sym) if flexmock_respond_to?(sym)
|
194
|
+
result = ExplicitNeeded.new(result, sym, @base_class) if
|
195
|
+
@base_class && ! @base_class.instance_methods.include?(sym)
|
165
196
|
result
|
166
197
|
end
|
167
|
-
@last_expectation
|
168
198
|
end
|
169
199
|
|
170
200
|
# Declare that the mock object should expect methods by providing a
|
data/lib/flexmock/errors.rb
CHANGED
data/lib/flexmock/expectation.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -10,6 +10,7 @@
|
|
10
10
|
#+++
|
11
11
|
|
12
12
|
require 'flexmock/noop'
|
13
|
+
require 'flexmock/argument_matching'
|
13
14
|
|
14
15
|
class FlexMock
|
15
16
|
|
@@ -127,18 +128,7 @@ class FlexMock
|
|
127
128
|
# Does the argument list match this expectation's argument
|
128
129
|
# specification.
|
129
130
|
def match_args(args)
|
130
|
-
|
131
|
-
# return false if @expected_args.nil?
|
132
|
-
return true if @expected_args.nil?
|
133
|
-
return false if args.size != @expected_args.size
|
134
|
-
(0...args.size).all? { |i| match_arg(@expected_args[i], args[i]) }
|
135
|
-
end
|
136
|
-
|
137
|
-
# Does the expected argument match the corresponding actual value.
|
138
|
-
def match_arg(expected, actual)
|
139
|
-
expected === actual ||
|
140
|
-
expected == actual ||
|
141
|
-
( Regexp === expected && expected === actual.to_s )
|
131
|
+
ArgumentMatching.all_match?(@expected_args, args)
|
142
132
|
end
|
143
133
|
|
144
134
|
# Declare that the method should expect the given argument list.
|
@@ -268,6 +258,12 @@ class FlexMock
|
|
268
258
|
end
|
269
259
|
alias :throws :and_throw
|
270
260
|
|
261
|
+
def pass_thru
|
262
|
+
and_return { |*args|
|
263
|
+
@mock.flexmock_invoke_original(@sym, args)
|
264
|
+
}
|
265
|
+
end
|
266
|
+
|
271
267
|
# Declare that the method may be called any number of times.
|
272
268
|
def zero_or_more_times
|
273
269
|
at_least.never
|
@@ -385,6 +381,12 @@ class FlexMock
|
|
385
381
|
end
|
386
382
|
private :define_ordered
|
387
383
|
|
384
|
+
# No-op for allowing explicit calls when explicit not explicitly
|
385
|
+
# needed.
|
386
|
+
def explicit
|
387
|
+
self
|
388
|
+
end
|
389
|
+
|
388
390
|
def by_default
|
389
391
|
expectations = mock.flexmock_expectations_for(@sym)
|
390
392
|
expectations.defaultify_expectation(self) if expectations
|