mocha 0.4.0 → 0.5.0
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/Rakefile +28 -10
- data/examples/stubba.rb +1 -1
- data/lib/mocha/auto_verify.rb +6 -6
- data/lib/mocha/deprecation.rb +22 -0
- data/lib/mocha/exception_raiser.rb +17 -0
- data/lib/mocha/expectation.rb +167 -84
- data/lib/mocha/infinite_range.rb +4 -6
- data/lib/mocha/inspect.rb +3 -1
- data/lib/mocha/is_a.rb +9 -0
- data/lib/mocha/missing_expectation.rb +27 -0
- data/lib/mocha/mock.rb +191 -5
- data/lib/mocha/multiple_yields.rb +20 -0
- data/lib/mocha/no_yields.rb +11 -0
- data/lib/mocha/object.rb +11 -1
- data/lib/mocha/parameter_matchers.rb +9 -0
- data/lib/mocha/parameter_matchers/all_of.rb +39 -0
- data/lib/mocha/parameter_matchers/any_of.rb +44 -0
- data/lib/mocha/parameter_matchers/anything.rb +30 -0
- data/lib/mocha/parameter_matchers/has_entry.rb +39 -0
- data/lib/mocha/parameter_matchers/has_key.rb +39 -0
- data/lib/mocha/parameter_matchers/has_value.rb +39 -0
- data/lib/mocha/parameter_matchers/includes.rb +37 -0
- data/lib/mocha/return_values.rb +31 -0
- data/lib/mocha/single_return_value.rb +24 -0
- data/lib/mocha/single_yield.rb +18 -0
- data/lib/mocha/standalone.rb +2 -0
- data/lib/mocha/stub.rb +18 -0
- data/lib/mocha/yield_parameters.rb +31 -0
- data/test/{mocha_acceptance_test.rb → acceptance/mocha_acceptance_test.rb} +1 -1
- data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +72 -0
- data/test/acceptance/parameter_matcher_acceptance_test.rb +63 -0
- data/test/{standalone_acceptance_test.rb → acceptance/standalone_acceptance_test.rb} +22 -1
- data/test/{stubba_acceptance_test.rb → acceptance/stubba_acceptance_test.rb} +1 -1
- data/test/deprecation_disabler.rb +15 -0
- data/test/{mocha_test_result_integration_test.rb → integration/mocha_test_result_integration_test.rb} +1 -1
- data/test/{stubba_integration_test.rb → integration/stubba_integration_test.rb} +1 -1
- data/test/{stubba_test_result_integration_test.rb → integration/stubba_test_result_integration_test.rb} +1 -1
- data/test/test_helper.rb +8 -0
- data/test/test_runner.rb +31 -0
- data/test/{mocha → unit}/any_instance_method_test.rb +0 -0
- data/test/unit/array_inspect_test.rb +16 -0
- data/test/{mocha → unit}/auto_verify_test.rb +0 -0
- data/test/{mocha → unit}/central_test.rb +0 -0
- data/test/{mocha → unit}/class_method_test.rb +0 -0
- data/test/unit/date_time_inspect_test.rb +21 -0
- data/test/unit/expectation_raiser_test.rb +28 -0
- data/test/{mocha → unit}/expectation_test.rb +105 -63
- data/test/unit/hash_inspect_test.rb +16 -0
- data/test/{mocha → unit}/infinite_range_test.rb +8 -5
- data/test/{mocha → unit}/metaclass_test.rb +0 -0
- data/test/unit/missing_expectation_test.rb +51 -0
- data/test/unit/mock_test.rb +351 -0
- data/test/unit/multiple_yields_test.rb +18 -0
- data/test/unit/no_yield_test.rb +18 -0
- data/test/unit/object_inspect_test.rb +35 -0
- data/test/{mocha → unit}/object_test.rb +0 -0
- data/test/unit/parameter_matchers/all_of_test.rb +26 -0
- data/test/unit/parameter_matchers/any_of_test.rb +26 -0
- data/test/unit/parameter_matchers/anything_test.rb +21 -0
- data/test/unit/parameter_matchers/has_entry_test.rb +25 -0
- data/test/unit/parameter_matchers/has_key_test.rb +25 -0
- data/test/unit/parameter_matchers/has_value_test.rb +25 -0
- data/test/unit/parameter_matchers/includes_test.rb +25 -0
- data/test/unit/parameter_matchers/stub_matcher.rb +22 -0
- data/test/{mocha → unit}/pretty_parameters_test.rb +0 -0
- data/test/unit/return_values_test.rb +63 -0
- data/test/{mocha → unit}/setup_and_teardown_test.rb +0 -0
- data/test/unit/single_return_value_test.rb +33 -0
- data/test/unit/single_yield_test.rb +18 -0
- data/test/unit/string_inspect_test.rb +11 -0
- data/test/unit/stub_test.rb +24 -0
- data/test/unit/yield_parameters_test.rb +93 -0
- metadata +117 -73
- data/lib/mocha/mock_methods.rb +0 -122
- data/test/all_tests.rb +0 -75
- data/test/mocha/inspect_test.rb +0 -90
- data/test/mocha/mock_methods_test.rb +0 -235
- data/test/mocha/mock_test.rb +0 -84
data/lib/mocha/infinite_range.rb
CHANGED
@@ -12,15 +12,13 @@ class Range
|
|
12
12
|
1/0.0
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
if first.to_f.infinite? then
|
15
|
+
def mocha_inspect
|
16
|
+
if first.respond_to?(:to_f) and first.to_f.infinite? then
|
19
17
|
return "at most #{last}"
|
20
|
-
elsif last.to_f.infinite? then
|
18
|
+
elsif last.respond_to?(:to_f) and last.to_f.infinite? then
|
21
19
|
return "at least #{first}"
|
22
20
|
else
|
23
|
-
|
21
|
+
to_s
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
data/lib/mocha/inspect.rb
CHANGED
@@ -2,7 +2,9 @@ require 'date'
|
|
2
2
|
|
3
3
|
class Object
|
4
4
|
def mocha_inspect
|
5
|
-
|
5
|
+
address = self.__id__ * 2
|
6
|
+
address += 0x100000000 if address < 0
|
7
|
+
inspect =~ /#</ ? "#<#{self.class}:0x#{'%x' % address}>" : inspect
|
6
8
|
end
|
7
9
|
end
|
8
10
|
|
data/lib/mocha/is_a.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'mocha/expectation'
|
2
|
+
|
3
|
+
module Mocha # :nodoc:
|
4
|
+
|
5
|
+
class MissingExpectation < Expectation # :nodoc:
|
6
|
+
|
7
|
+
def initialize(mock, method_name)
|
8
|
+
super
|
9
|
+
@invoked_count = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def verify
|
13
|
+
msg = error_message(0, 1)
|
14
|
+
similar_expectations_list = similar_expectations.collect { |expectation| expectation.method_signature }.join("\n")
|
15
|
+
msg << "\nSimilar expectations:\n#{similar_expectations_list}" unless similar_expectations.empty?
|
16
|
+
error = ExpectationError.new(msg)
|
17
|
+
error.set_backtrace(filtered_backtrace)
|
18
|
+
raise error if @invoked_count
|
19
|
+
end
|
20
|
+
|
21
|
+
def similar_expectations
|
22
|
+
@mock.expectations.select { |expectation| expectation.method_name == self.method_name }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/mocha/mock.rb
CHANGED
@@ -1,19 +1,205 @@
|
|
1
|
-
require 'mocha/
|
1
|
+
require 'mocha/expectation'
|
2
|
+
require 'mocha/stub'
|
3
|
+
require 'mocha/missing_expectation'
|
4
|
+
require 'mocha/metaclass'
|
2
5
|
|
3
|
-
module Mocha
|
6
|
+
module Mocha # :nodoc:
|
4
7
|
|
8
|
+
# Traditional mock object.
|
9
|
+
#
|
10
|
+
# Methods return an Expectation which can be further modified by methods on Expectation.
|
5
11
|
class Mock
|
6
12
|
|
7
|
-
|
8
|
-
|
13
|
+
# :stopdoc:
|
14
|
+
|
9
15
|
def initialize(stub_everything = false, name = nil)
|
10
16
|
@stub_everything = stub_everything
|
11
17
|
@mock_name = name
|
18
|
+
@expectations = []
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :stub_everything, :expectations
|
22
|
+
|
23
|
+
# :startdoc:
|
24
|
+
|
25
|
+
# :call-seq: expects(method_name) -> expectation
|
26
|
+
# expects(method_names) -> last expectation
|
27
|
+
#
|
28
|
+
# Adds an expectation that a method identified by +method_name+ symbol must be called exactly once with any parameters.
|
29
|
+
# Returns the new expectation which can be further modified by methods on Expectation.
|
30
|
+
# object = mock()
|
31
|
+
# object.expects(:method1)
|
32
|
+
# object.method1
|
33
|
+
# # no error raised
|
34
|
+
#
|
35
|
+
# object = mock()
|
36
|
+
# object.expects(:method1)
|
37
|
+
# # error raised, because method1 not called exactly once
|
38
|
+
# If +method_names+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
|
39
|
+
# object = mock()
|
40
|
+
# object.expects(:method1 => :result1, :method2 => :result2)
|
41
|
+
#
|
42
|
+
# # exactly equivalent to
|
43
|
+
#
|
44
|
+
# object = mock()
|
45
|
+
# object.expects(:method1).returns(:result1)
|
46
|
+
# object.expects(:method2).returns(:result2)
|
47
|
+
#
|
48
|
+
# Aliased by <tt>\_\_expects\_\_</tt>
|
49
|
+
def expects(method_name_or_hash, backtrace = nil)
|
50
|
+
if method_name_or_hash.is_a?(Hash) then
|
51
|
+
method_name_or_hash.each do |method_name, return_value|
|
52
|
+
add_expectation(Expectation.new(self, method_name, backtrace).returns(return_value))
|
53
|
+
end
|
54
|
+
else
|
55
|
+
add_expectation(Expectation.new(self, method_name_or_hash, backtrace))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# :call-seq: stubs(method_name) -> expectation
|
60
|
+
# stubs(method_names) -> last expectation
|
61
|
+
#
|
62
|
+
# Adds an expectation that a method identified by +method_name+ symbol may be called any number of times with any parameters.
|
63
|
+
# Returns the new expectation which can be further modified by methods on Expectation.
|
64
|
+
# object = mock()
|
65
|
+
# object.stubs(:method1)
|
66
|
+
# object.method1
|
67
|
+
# object.method1
|
68
|
+
# # no error raised
|
69
|
+
# If +method_names+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
|
70
|
+
# object = mock()
|
71
|
+
# object.stubs(:method1 => :result1, :method2 => :result2)
|
72
|
+
#
|
73
|
+
# # exactly equivalent to
|
74
|
+
#
|
75
|
+
# object = mock()
|
76
|
+
# object.stubs(:method1).returns(:result1)
|
77
|
+
# object.stubs(:method2).returns(:result2)
|
78
|
+
#
|
79
|
+
# Aliased by <tt>\_\_stubs\_\_</tt>
|
80
|
+
def stubs(method_name_or_hash, backtrace = nil)
|
81
|
+
if method_name_or_hash.is_a?(Hash) then
|
82
|
+
method_name_or_hash.each do |method_name, return_value|
|
83
|
+
add_expectation(Stub.new(self, method_name, backtrace).returns(return_value))
|
84
|
+
end
|
85
|
+
else
|
86
|
+
add_expectation(Stub.new(self, method_name_or_hash, backtrace))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# :call-seq: responds_like(responder) -> mock
|
91
|
+
#
|
92
|
+
# Constrains the +mock+ so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
|
93
|
+
#
|
94
|
+
# A +NoMethodError+ will be raised if the +responder+ does not <tt>respond_to?</tt> a method invocation (even if the method has been expected or stubbed).
|
95
|
+
#
|
96
|
+
# The +mock+ will delegate its <tt>respond_to?</tt> method to the +responder+.
|
97
|
+
# class Sheep
|
98
|
+
# def chew(grass); end
|
99
|
+
# def self.number_of_legs; end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# sheep = mock('sheep')
|
103
|
+
# sheep.expects(:chew)
|
104
|
+
# sheep.expects(:foo)
|
105
|
+
# sheep.respond_to?(:chew) # => true
|
106
|
+
# sheep.respond_to?(:foo) # => true
|
107
|
+
# sheep.chew
|
108
|
+
# sheep.foo
|
109
|
+
# # no error raised
|
110
|
+
#
|
111
|
+
# sheep = mock('sheep')
|
112
|
+
# sheep.responds_like(Sheep.new)
|
113
|
+
# sheep.expects(:chew)
|
114
|
+
# sheep.expects(:foo)
|
115
|
+
# sheep.respond_to?(:chew) # => true
|
116
|
+
# sheep.respond_to?(:foo) # => false
|
117
|
+
# sheep.chew
|
118
|
+
# sheep.foo # => raises NoMethodError exception
|
119
|
+
#
|
120
|
+
# sheep_class = mock('sheep_class')
|
121
|
+
# sheep_class.responds_like(Sheep)
|
122
|
+
# sheep_class.stubs(:number_of_legs).returns(4)
|
123
|
+
# sheep_class.expects(:foo)
|
124
|
+
# sheep_class.respond_to?(:number_of_legs) # => true
|
125
|
+
# sheep_class.respond_to?(:foo) # => false
|
126
|
+
# assert_equal 4, sheep_class.number_of_legs
|
127
|
+
# sheep_class.foo # => raises NoMethodError exception
|
128
|
+
#
|
129
|
+
# Aliased by +quacks_like+
|
130
|
+
def responds_like(object)
|
131
|
+
@responder = object
|
132
|
+
self
|
12
133
|
end
|
134
|
+
|
135
|
+
# :stopdoc:
|
136
|
+
|
137
|
+
alias_method :__expects__, :expects
|
13
138
|
|
139
|
+
alias_method :__stubs__, :stubs
|
140
|
+
|
141
|
+
alias_method :quacks_like, :responds_like
|
142
|
+
|
143
|
+
def add_expectation(expectation)
|
144
|
+
@expectations << expectation
|
145
|
+
method_name = expectation.method_name
|
146
|
+
self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name)
|
147
|
+
expectation
|
148
|
+
end
|
149
|
+
|
150
|
+
def method_missing(symbol, *arguments, &block)
|
151
|
+
if @responder and not @responder.respond_to?(symbol)
|
152
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
|
153
|
+
end
|
154
|
+
matching_expectation = matching_expectation(symbol, *arguments)
|
155
|
+
if matching_expectation then
|
156
|
+
matching_expectation.invoke(&block)
|
157
|
+
elsif stub_everything then
|
158
|
+
return
|
159
|
+
else
|
160
|
+
begin
|
161
|
+
super_method_missing(symbol, *arguments, &block)
|
162
|
+
rescue NoMethodError
|
163
|
+
unexpected_method_called(symbol, *arguments)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def respond_to?(symbol)
|
169
|
+
if @responder then
|
170
|
+
@responder.respond_to?(symbol)
|
171
|
+
else
|
172
|
+
@expectations.any? { |expectation| expectation.method_name == symbol }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def super_method_missing(symbol, *arguments, &block)
|
177
|
+
raise NoMethodError
|
178
|
+
end
|
179
|
+
|
180
|
+
def unexpected_method_called(symbol, *arguments)
|
181
|
+
MissingExpectation.new(self, symbol).with(*arguments).verify
|
182
|
+
end
|
183
|
+
|
184
|
+
def matching_expectation(symbol, *arguments)
|
185
|
+
@expectations.reverse.detect { |expectation| expectation.match?(symbol, *arguments) }
|
186
|
+
end
|
187
|
+
|
188
|
+
def verify(&block)
|
189
|
+
@expectations.each { |expectation| expectation.verify(&block) }
|
190
|
+
end
|
191
|
+
|
14
192
|
def mocha_inspect
|
15
|
-
|
193
|
+
address = self.__id__ * 2
|
194
|
+
address += 0x100000000 if address < 0
|
195
|
+
@mock_name ? "#<Mock:#{@mock_name}>" : "#<Mock:0x#{'%x' % address}>"
|
16
196
|
end
|
197
|
+
|
198
|
+
def inspect
|
199
|
+
mocha_inspect
|
200
|
+
end
|
201
|
+
|
202
|
+
# :startdoc:
|
17
203
|
|
18
204
|
end
|
19
205
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Mocha # :nodoc:
|
2
|
+
|
3
|
+
class MultipleYields # :nodoc:
|
4
|
+
|
5
|
+
attr_reader :parameter_groups
|
6
|
+
|
7
|
+
def initialize(*parameter_groups)
|
8
|
+
@parameter_groups = parameter_groups
|
9
|
+
end
|
10
|
+
|
11
|
+
def each
|
12
|
+
@parameter_groups.each do |parameter_group|
|
13
|
+
yield(parameter_group)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
data/lib/mocha/object.rb
CHANGED
@@ -3,7 +3,9 @@ require 'mocha/instance_method'
|
|
3
3
|
require 'mocha/class_method'
|
4
4
|
require 'mocha/any_instance_method'
|
5
5
|
|
6
|
-
# Methods added all
|
6
|
+
# Methods added all objects to allow mocking and stubbing on real objects.
|
7
|
+
#
|
8
|
+
# Methods return a Mocha::Expectation which can be further modified by methods on Mocha::Expectation.
|
7
9
|
class Object
|
8
10
|
|
9
11
|
def mocha # :nodoc:
|
@@ -29,6 +31,10 @@ class Object
|
|
29
31
|
# product = Product.new
|
30
32
|
# product.expects(:save).returns(true)
|
31
33
|
# assert_equal false, product.save
|
34
|
+
#
|
35
|
+
# The original implementation of <tt>Product#save</tt> is replaced temporarily.
|
36
|
+
#
|
37
|
+
# The original implementation of <tt>Product#save</tt> is restored at the end of the test.
|
32
38
|
def expects(symbol)
|
33
39
|
method = stubba_method.new(stubba_object, symbol)
|
34
40
|
$stubba.stub(method)
|
@@ -42,6 +48,10 @@ class Object
|
|
42
48
|
# product = Product.new
|
43
49
|
# product.stubs(:save).returns(true)
|
44
50
|
# assert_equal false, product.save
|
51
|
+
#
|
52
|
+
# The original implementation of <tt>Product#save</tt> is replaced temporarily.
|
53
|
+
#
|
54
|
+
# The original implementation of <tt>Product#save</tt> is restored at the end of the test.
|
45
55
|
def stubs(symbol)
|
46
56
|
method = stubba_method.new(stubba_object, symbol)
|
47
57
|
$stubba.stub(method)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Mocha
|
2
|
+
|
3
|
+
# Used as parameters for Expectation#with to restrict the parameter values which will match the expectation.
|
4
|
+
module ParameterMatchers; end
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__), 'parameter_matchers', "*.rb"))].each { |lib| require lib }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Mocha
|
2
|
+
|
3
|
+
module ParameterMatchers
|
4
|
+
|
5
|
+
# :call-seq: all_of -> parameter_matcher
|
6
|
+
#
|
7
|
+
# Matches if all +matchers+ match.
|
8
|
+
# object = mock()
|
9
|
+
# object.expects(:method_1).with(all_of(includes(1), includes(3)))
|
10
|
+
# object.method_1([1, 3])
|
11
|
+
# # no error raised
|
12
|
+
#
|
13
|
+
# object = mock()
|
14
|
+
# object.expects(:method_1).with(all_of(includes(1), includes(3)))
|
15
|
+
# object.method_1([1, 2])
|
16
|
+
# # error raised, because method_1 was not called with object including 1 and 3
|
17
|
+
def all_of(*matchers)
|
18
|
+
AllOf.new(*matchers)
|
19
|
+
end
|
20
|
+
|
21
|
+
class AllOf # :nodoc:
|
22
|
+
|
23
|
+
def initialize(*matchers)
|
24
|
+
@matchers = matchers
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(parameter)
|
28
|
+
@matchers.all? { |matcher| matcher == parameter }
|
29
|
+
end
|
30
|
+
|
31
|
+
def mocha_inspect
|
32
|
+
"all_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Mocha
|
2
|
+
|
3
|
+
module ParameterMatchers
|
4
|
+
|
5
|
+
# :call-seq: any_of -> parameter_matcher
|
6
|
+
#
|
7
|
+
# Matches if any +matchers+ match.
|
8
|
+
# object = mock()
|
9
|
+
# object.expects(:method_1).with(any_of(1, 3))
|
10
|
+
# object.method_1(1)
|
11
|
+
# # no error raised
|
12
|
+
#
|
13
|
+
# object = mock()
|
14
|
+
# object.expects(:method_1).with(any_of(1, 3))
|
15
|
+
# object.method_1(3)
|
16
|
+
# # no error raised
|
17
|
+
#
|
18
|
+
# object = mock()
|
19
|
+
# object.expects(:method_1).with(any_of(1, 3))
|
20
|
+
# object.method_1(2)
|
21
|
+
# # error raised, because method_1 was not called with 1 or 3
|
22
|
+
def any_of(*matchers)
|
23
|
+
AnyOf.new(*matchers)
|
24
|
+
end
|
25
|
+
|
26
|
+
class AnyOf # :nodoc:
|
27
|
+
|
28
|
+
def initialize(*matchers)
|
29
|
+
@matchers = matchers
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(parameter)
|
33
|
+
@matchers.any? { |matcher| matcher == parameter }
|
34
|
+
end
|
35
|
+
|
36
|
+
def mocha_inspect
|
37
|
+
"any_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|