rspec-mocks 2.99.4 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +14 -6
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +1 -0
- data/Changelog.md +89 -105
- data/License.txt +1 -0
- data/README.md +77 -57
- data/features/argument_matchers/explicit.feature +5 -5
- data/features/argument_matchers/general_matchers.feature +10 -10
- data/features/argument_matchers/type_matchers.feature +3 -3
- data/features/message_expectations/allow_any_instance_of.feature +1 -1
- data/features/message_expectations/any_instance.feature +27 -5
- data/features/message_expectations/call_original.feature +2 -2
- data/features/message_expectations/expect_message_using_expect.feature +2 -2
- data/features/message_expectations/expect_message_using_should_receive.feature +2 -2
- data/features/message_expectations/receive_counts.feature +7 -7
- data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +3 -3
- data/features/method_stubs/README.md +3 -0
- data/features/method_stubs/any_instance.feature +11 -11
- data/features/method_stubs/as_null_object.feature +4 -4
- data/features/method_stubs/simple_return_value_with_stub.feature +7 -7
- data/features/method_stubs/stub_chain.feature +3 -3
- data/features/method_stubs/stub_implementation.feature +2 -2
- data/features/method_stubs/to_ary.feature +2 -2
- data/features/mutating_constants/hiding_defined_constant.feature +2 -2
- data/features/mutating_constants/stub_defined_constant.feature +5 -5
- data/features/mutating_constants/stub_undefined_constant.feature +6 -6
- data/features/outside_rspec/configuration.feature +0 -2
- data/features/outside_rspec/standalone.feature +1 -1
- data/features/spies/spy_partial_mock_method.feature +2 -2
- data/features/spies/spy_pure_mock_method.feature +5 -5
- data/features/spies/spy_unstubbed_method.feature +1 -1
- data/features/support/env.rb +10 -1
- data/features/test_frameworks/test_unit.feature +1 -1
- data/features/verifying_doubles/class_doubles.feature +88 -0
- data/features/verifying_doubles/dynamic_classes.feature +72 -0
- data/features/verifying_doubles/introduction.feature +85 -0
- data/features/verifying_doubles/object_doubles.feature +65 -0
- data/features/verifying_doubles/partial_doubles.feature +34 -0
- data/lib/rspec/mocks.rb +8 -34
- data/lib/rspec/mocks/any_instance/chain.rb +4 -34
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +14 -4
- data/lib/rspec/mocks/any_instance/message_chains.rb +27 -12
- data/lib/rspec/mocks/any_instance/recorder.rb +23 -31
- data/lib/rspec/mocks/any_instance/stub_chain.rb +9 -4
- data/lib/rspec/mocks/argument_list_matcher.rb +8 -1
- data/lib/rspec/mocks/argument_matchers.rb +26 -12
- data/lib/rspec/mocks/arity_calculator.rb +66 -0
- data/lib/rspec/mocks/configuration.rb +42 -14
- data/lib/rspec/mocks/error_generator.rb +34 -10
- data/lib/rspec/mocks/example_methods.rb +64 -19
- data/lib/rspec/mocks/extensions/marshal.rb +0 -15
- data/lib/rspec/mocks/framework.rb +4 -4
- data/lib/rspec/mocks/instance_method_stasher.rb +80 -62
- data/lib/rspec/mocks/matchers/have_received.rb +18 -14
- data/lib/rspec/mocks/matchers/receive.rb +29 -7
- data/lib/rspec/mocks/matchers/receive_messages.rb +72 -0
- data/lib/rspec/mocks/message_expectation.rb +95 -148
- data/lib/rspec/mocks/method_double.rb +77 -139
- data/lib/rspec/mocks/method_reference.rb +95 -0
- data/lib/rspec/mocks/mock.rb +1 -1
- data/lib/rspec/mocks/mutate_const.rb +12 -9
- data/lib/rspec/mocks/object_reference.rb +90 -0
- data/lib/rspec/mocks/order_group.rb +49 -7
- data/lib/rspec/mocks/proxy.rb +72 -33
- data/lib/rspec/mocks/proxy_for_nil.rb +2 -2
- data/lib/rspec/mocks/space.rb +13 -18
- data/lib/rspec/mocks/stub_chain.rb +2 -2
- data/lib/rspec/mocks/syntax.rb +61 -36
- data/lib/rspec/mocks/targets.rb +40 -19
- data/lib/rspec/mocks/test_double.rb +12 -56
- data/lib/rspec/mocks/verifying_double.rb +77 -0
- data/lib/rspec/mocks/verifying_message_expecation.rb +60 -0
- data/lib/rspec/mocks/verifying_proxy.rb +151 -0
- data/lib/rspec/mocks/version.rb +1 -1
- data/spec/rspec/mocks/and_call_original_spec.rb +34 -30
- data/spec/rspec/mocks/and_yield_spec.rb +2 -2
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
- data/spec/rspec/mocks/any_instance_spec.rb +53 -260
- data/spec/rspec/mocks/argument_expectation_spec.rb +4 -4
- data/spec/rspec/mocks/arity_calculator_spec.rb +95 -0
- data/spec/rspec/mocks/array_including_matcher_spec.rb +41 -0
- data/spec/rspec/mocks/at_least_spec.rb +4 -32
- data/spec/rspec/mocks/block_return_value_spec.rb +4 -135
- data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +10 -11
- data/spec/rspec/mocks/configuration_spec.rb +79 -0
- data/spec/rspec/mocks/double_spec.rb +10 -78
- data/spec/rspec/mocks/extensions/marshal_spec.rb +0 -8
- data/spec/rspec/mocks/failing_argument_matchers_spec.rb +49 -4
- data/spec/rspec/mocks/instance_method_stasher_spec.rb +20 -3
- data/spec/rspec/mocks/matchers/have_received_spec.rb +74 -0
- data/spec/rspec/mocks/matchers/receive_messages_spec.rb +140 -0
- data/spec/rspec/mocks/matchers/receive_spec.rb +82 -42
- data/spec/rspec/mocks/methods_spec.rb +1 -1
- data/spec/rspec/mocks/{bug_report_830_spec.rb → mock_expectation_error_spec.rb} +4 -3
- data/spec/rspec/mocks/mock_ordering_spec.rb +11 -0
- data/spec/rspec/mocks/mock_space_spec.rb +10 -1
- data/spec/rspec/mocks/mock_spec.rb +26 -82
- data/spec/rspec/mocks/multiple_return_value_spec.rb +1 -1
- data/spec/rspec/mocks/mutate_const_spec.rb +18 -5
- data/spec/rspec/mocks/null_object_mock_spec.rb +6 -4
- data/spec/rspec/mocks/options_hash_spec.rb +3 -3
- data/spec/rspec/mocks/order_group_spec.rb +27 -0
- data/spec/rspec/mocks/partial_mock_spec.rb +101 -1
- data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -20
- data/spec/rspec/mocks/record_messages_spec.rb +4 -4
- data/spec/rspec/mocks/serialization_spec.rb +4 -6
- data/spec/rspec/mocks/space_spec.rb +3 -3
- data/spec/rspec/mocks/stub_chain_spec.rb +0 -12
- data/spec/rspec/mocks/stub_spec.rb +23 -44
- data/spec/rspec/mocks/test_double_spec.rb +3 -22
- data/spec/rspec/mocks/verifying_double_spec.rb +327 -0
- data/spec/rspec/mocks/verifying_message_expecation_spec.rb +68 -0
- data/spec/rspec/mocks_spec.rb +16 -39
- data/spec/spec_helper.rb +29 -18
- metadata +131 -86
- metadata.gz.sig +1 -0
- data/features/message_expectations/expect_any_instance_of.feature +0 -27
- data/lib/rspec/mocks/caller_filter.rb +0 -60
- data/lib/rspec/mocks/deprecation.rb +0 -26
- data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
- data/lib/rspec/mocks/extensions/proc.rb +0 -63
- data/lib/spec/mocks.rb +0 -4
- data/spec/rspec/mocks/and_return_spec.rb +0 -17
- data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -36
- data/spec/rspec/mocks/before_all_spec.rb +0 -74
- data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
- data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -27
- data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
- data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
- data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
- data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
- data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
- data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rspec/mocks/arity_calculator'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
|
6
|
+
# A message expectation that knows about the real implementation of the
|
7
|
+
# message being expected, so that it can verify that any expectations
|
8
|
+
# have the correct arity.
|
9
|
+
class VerifyingMessageExpectation < MessageExpectation
|
10
|
+
|
11
|
+
# A level of indirection is used here rather than just passing in the
|
12
|
+
# method itself, since method look up is expensive and we only want to
|
13
|
+
# do it if actually needed.
|
14
|
+
#
|
15
|
+
# Conceptually the method reference makes more sense as a constructor
|
16
|
+
# argument since it should be immutable, but it is significantly more
|
17
|
+
# straight forward to build the object in pieces so for now it stays as
|
18
|
+
# an accessor.
|
19
|
+
attr_accessor :method_reference
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
# @override
|
26
|
+
def with(*args, &block)
|
27
|
+
unless ArgumentMatchers::AnyArgsMatcher === args.first
|
28
|
+
expected_arity = if ArgumentMatchers::NoArgsMatcher === args.first
|
29
|
+
0
|
30
|
+
elsif args.length > 0
|
31
|
+
args.length
|
32
|
+
else
|
33
|
+
# No arguments given, this will raise.
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
ensure_arity!(expected_arity)
|
38
|
+
end
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def ensure_arity!(actual)
|
45
|
+
return if method_reference.nil?
|
46
|
+
|
47
|
+
method_reference.when_defined do |method|
|
48
|
+
calculator = ArityCalculator.new(method)
|
49
|
+
unless calculator.within_range?(actual)
|
50
|
+
# Fail fast is required, otherwise the message expecation will fail
|
51
|
+
# as well ("expected method not called") and clobber this one.
|
52
|
+
@failed_fast = true
|
53
|
+
@error_generator.raise_arity_error(calculator, actual)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'rspec/mocks/verifying_message_expecation'
|
2
|
+
require 'rspec/mocks/method_reference'
|
3
|
+
|
4
|
+
module RSpec
|
5
|
+
module Mocks
|
6
|
+
|
7
|
+
module VerifyingProxyMethods
|
8
|
+
def add_stub(location, method_name, opts={}, &implementation)
|
9
|
+
ensure_implemented(method_name)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_simple_stub(method_name, *args)
|
14
|
+
ensure_implemented(method_name)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_message_expectation(location, method_name, opts={}, &block)
|
19
|
+
ensure_implemented(method_name)
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def ensure_implemented(method_name)
|
24
|
+
return unless @doubled_module.defined?
|
25
|
+
|
26
|
+
method_reference[method_name].when_unimplemented do
|
27
|
+
@error_generator.raise_unimplemented_error(
|
28
|
+
@doubled_module,
|
29
|
+
method_name
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# A verifying proxy mostly acts like a normal proxy, except that it
|
36
|
+
# contains extra logic to try and determine the validity of any expectation
|
37
|
+
# set on it. This includes whether or not methods have been defined and the
|
38
|
+
# arity of method calls.
|
39
|
+
#
|
40
|
+
# In all other ways this behaves like a normal proxy. It only adds the
|
41
|
+
# verification behaviour to specific methods then delegates to the parent
|
42
|
+
# implementation.
|
43
|
+
#
|
44
|
+
# These checks are only activated if the doubled class has already been
|
45
|
+
# loaded, otherwise they are disabled. This allows for testing in
|
46
|
+
# isolation.
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
class VerifyingProxy < Proxy
|
50
|
+
include VerifyingProxyMethods
|
51
|
+
|
52
|
+
def initialize(object, order_group, name, method_reference_class)
|
53
|
+
super(object, order_group)
|
54
|
+
@object = object
|
55
|
+
@doubled_module = name
|
56
|
+
@method_reference_class = method_reference_class
|
57
|
+
|
58
|
+
# A custom method double is required to pass through a way to lookup
|
59
|
+
# methods to determine their arity. This is only relevant if the doubled
|
60
|
+
# class is loaded.
|
61
|
+
@method_doubles = Hash.new do |h, k|
|
62
|
+
h[k] = VerifyingMethodDouble.new(@object, k, self, method_reference[k])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def method_reference
|
67
|
+
@method_reference ||= Hash.new do |h, k|
|
68
|
+
h[k] = @method_reference_class.new(@doubled_module, k)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class VerifyingPartialMockProxy < PartialMockProxy
|
74
|
+
include VerifyingProxyMethods
|
75
|
+
|
76
|
+
def initialize(object, expectation_ordering)
|
77
|
+
super(object, expectation_ordering)
|
78
|
+
@doubled_module = DirectObjectReference.new(object)
|
79
|
+
|
80
|
+
# A custom method double is required to pass through a way to lookup
|
81
|
+
# methods to determine their arity.
|
82
|
+
@method_doubles = Hash.new do |h, k|
|
83
|
+
h[k] = VerifyingExistingMethodDouble.new(object, k, self)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def method_reference
|
88
|
+
@method_doubles
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
class VerifyingMethodDouble < MethodDouble
|
94
|
+
def initialize(object, method_name, proxy, method_reference)
|
95
|
+
super(object, method_name, proxy)
|
96
|
+
@method_reference = method_reference
|
97
|
+
end
|
98
|
+
|
99
|
+
def message_expectation_class
|
100
|
+
VerifyingMessageExpectation
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_expectation(*arg)
|
104
|
+
super.tap { |x| x.method_reference = @method_reference }
|
105
|
+
end
|
106
|
+
|
107
|
+
def proxy_method_invoked(obj, *args, &block)
|
108
|
+
ensure_arity!(args.length)
|
109
|
+
super
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def ensure_arity!(arity)
|
115
|
+
@method_reference.when_defined do |method|
|
116
|
+
calculator = ArityCalculator.new(method)
|
117
|
+
unless calculator.within_range?(arity)
|
118
|
+
raise ArgumentError, "wrong number of arguments (#{arity} for #{method.arity})"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# @api private
|
125
|
+
#
|
126
|
+
# A VerifyingMethodDouble fetches the method to verify against from the
|
127
|
+
# original object, using a MethodReference. This works for pure doubles,
|
128
|
+
# but when the original object is itself the one being modified we need to
|
129
|
+
# collapse the reference and the method double into a single object so that
|
130
|
+
# we can access the original pristine method definition.
|
131
|
+
class VerifyingExistingMethodDouble < VerifyingMethodDouble
|
132
|
+
def initialize(object, method_name, proxy)
|
133
|
+
super(object, method_name, proxy, self)
|
134
|
+
|
135
|
+
@valid_method = object.respond_to?(method_name)
|
136
|
+
|
137
|
+
# Trigger an eager find of the original method since if we find it any
|
138
|
+
# later we end up getting a stubbed method with incorrect arity.
|
139
|
+
save_original_method!
|
140
|
+
end
|
141
|
+
|
142
|
+
def when_defined
|
143
|
+
yield original_method
|
144
|
+
end
|
145
|
+
|
146
|
+
def when_unimplemented
|
147
|
+
yield unless @valid_method
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
data/lib/rspec/mocks/version.rb
CHANGED
@@ -22,24 +22,36 @@ describe "and_call_original" do
|
|
22
22
|
let(:instance) { klass.new }
|
23
23
|
|
24
24
|
it 'passes the received message through to the original method' do
|
25
|
+
expect(instance).to receive(:meth_1).and_call_original
|
26
|
+
expect(instance.meth_1).to eq(:original)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'ignores prior declared stubs' do
|
30
|
+
instance.stub(:meth_1).and_return(:stubbed_value)
|
25
31
|
instance.should_receive(:meth_1).and_call_original
|
26
32
|
expect(instance.meth_1).to eq(:original)
|
27
33
|
end
|
28
34
|
|
29
35
|
it 'passes args and blocks through to the original method' do
|
30
|
-
instance.
|
36
|
+
expect(instance).to receive(:meth_2).and_call_original
|
31
37
|
value = instance.meth_2(:submitted_arg) { |a, b| [a, b] }
|
32
38
|
expect(value).to eq([:submitted_arg, :additional_yielded_arg])
|
33
39
|
end
|
34
40
|
|
35
41
|
it 'errors when you pass through the wrong number of args' do
|
36
|
-
instance.
|
37
|
-
instance.
|
42
|
+
expect(instance).to receive(:meth_1).and_call_original
|
43
|
+
expect(instance).to receive(:meth_2).twice.and_call_original
|
38
44
|
expect { instance.meth_1 :a }.to raise_error ArgumentError
|
39
45
|
expect { instance.meth_2 {} }.to raise_error ArgumentError
|
40
46
|
expect { instance.meth_2(:a, :b) {} }.to raise_error ArgumentError
|
41
47
|
end
|
42
48
|
|
49
|
+
it 'warns when you override an existing implementation' do
|
50
|
+
expect(RSpec).to receive(:warning).with(/overriding a previous implementation/)
|
51
|
+
expect(instance).to receive(:meth_1) { true }.and_call_original
|
52
|
+
instance.meth_1
|
53
|
+
end
|
54
|
+
|
43
55
|
context "for singleton methods" do
|
44
56
|
it 'works' do
|
45
57
|
def instance.foo; :bar; end
|
@@ -77,6 +89,15 @@ describe "and_call_original" do
|
|
77
89
|
expect(sub_klass.foo).to eq(:sub_klass_bar)
|
78
90
|
end
|
79
91
|
|
92
|
+
it "finds the method on the most direct singleton class ancestors even if the method " +
|
93
|
+
"is available on more distant ancestors" do
|
94
|
+
klass.extend Module.new { def foo; :klass_bar; end }
|
95
|
+
sub_klass = Class.new(klass) { def self.foo; :sub_klass_bar; end }
|
96
|
+
sub_sub_klass = Class.new(sub_klass)
|
97
|
+
sub_sub_klass.should_receive(:foo).and_call_original
|
98
|
+
expect(sub_sub_klass.foo).to eq(:sub_klass_bar)
|
99
|
+
end
|
100
|
+
|
80
101
|
context 'when using any_instance' do
|
81
102
|
it 'works for instance methods defined on the class' do
|
82
103
|
klass.any_instance.should_receive(:meth_1).and_call_original
|
@@ -95,33 +116,16 @@ describe "and_call_original" do
|
|
95
116
|
end
|
96
117
|
end
|
97
118
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'works for class methods defined on a grandparent class' do
|
106
|
-
sub_subclass = Class.new(Class.new(klass))
|
107
|
-
sub_subclass.should_receive(:new_instance).and_call_original
|
108
|
-
expect(sub_subclass.new_instance).to be_a(sub_subclass)
|
109
|
-
end
|
110
|
-
else
|
111
|
-
it 'attempts to work for class methods defined on a superclass but ' +
|
112
|
-
'executes the method with `self` as the superclass' do
|
113
|
-
::Kernel.stub(:warn)
|
114
|
-
subclass = Class.new(klass)
|
115
|
-
subclass.should_receive(:new_instance).and_call_original
|
116
|
-
expect(subclass.new_instance).to be_an_instance_of(klass)
|
117
|
-
end
|
119
|
+
it 'works for class methods defined on a superclass' do
|
120
|
+
subclass = Class.new(klass)
|
121
|
+
subclass.should_receive(:new_instance).and_call_original
|
122
|
+
expect(subclass.new_instance).to be_a(subclass)
|
123
|
+
end
|
118
124
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
subclass.new_instance
|
124
|
-
end
|
125
|
+
it 'works for class methods defined on a grandparent class' do
|
126
|
+
sub_subclass = Class.new(Class.new(klass))
|
127
|
+
sub_subclass.should_receive(:new_instance).and_call_original
|
128
|
+
expect(sub_subclass.new_instance).to be_a(sub_subclass)
|
125
129
|
end
|
126
130
|
|
127
131
|
it 'works for class methods defined on the Class class' do
|
@@ -149,7 +153,7 @@ describe "and_call_original" do
|
|
149
153
|
|
150
154
|
context 'on an object that defines method_missing' do
|
151
155
|
before do
|
152
|
-
klass.
|
156
|
+
klass.class_exec do
|
153
157
|
private
|
154
158
|
|
155
159
|
def method_missing(name, *args)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe RSpec::Mocks::
|
3
|
+
describe RSpec::Mocks::Mock do
|
4
4
|
|
5
5
|
let(:obj) { double }
|
6
6
|
|
@@ -25,7 +25,7 @@ describe RSpec::Mocks::Double do
|
|
25
25
|
obj.stub(:method_that_accepts_a_block).and_yield do |eval_context|
|
26
26
|
evaluated = true
|
27
27
|
end
|
28
|
-
expect(evaluated).to
|
28
|
+
expect(evaluated).to be_truthy
|
29
29
|
end
|
30
30
|
|
31
31
|
it "passes an eval context object to the supplied block" do
|
@@ -4,7 +4,7 @@ describe RSpec::Mocks::AnyInstance::MessageChains do
|
|
4
4
|
let(:recorder) { double }
|
5
5
|
let(:chains) { RSpec::Mocks::AnyInstance::MessageChains.new }
|
6
6
|
let(:stub_chain) { RSpec::Mocks::AnyInstance::StubChain.new recorder }
|
7
|
-
let(:expectation_chain) { RSpec::Mocks::AnyInstance::
|
7
|
+
let(:expectation_chain) { RSpec::Mocks::AnyInstance::PositiveExpectationChain.new recorder }
|
8
8
|
|
9
9
|
it "knows if a method does not have an expectation set on it" do
|
10
10
|
chains.add(:method_name, stub_chain)
|
@@ -37,7 +37,7 @@ module RSpec
|
|
37
37
|
end
|
38
38
|
|
39
39
|
context "#stub_chain" do
|
40
|
-
it "raises an error if 'stub_chain' follows '
|
40
|
+
it "raises an error if 'stub_chain' follows 'and_return'" do
|
41
41
|
expect { klass.any_instance.and_return("1").stub_chain(:foo, :bar) }.to raise_error(NoMethodError)
|
42
42
|
end
|
43
43
|
end
|
@@ -48,12 +48,12 @@ module RSpec
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "raises an error if 'with' follows 'and_return'" do
|
51
|
-
|
51
|
+
pending "see Github issue #42"
|
52
52
|
expect { klass.any_instance.should_receive(:foo).and_return(1).with("1") }.to raise_error(NoMethodError)
|
53
53
|
end
|
54
54
|
|
55
55
|
it "raises an error if 'with' follows 'and_raise'" do
|
56
|
-
|
56
|
+
pending "see Github issue #42"
|
57
57
|
expect { klass.any_instance.should_receive(:foo).and_raise(1).with("1") }.to raise_error(NoMethodError)
|
58
58
|
end
|
59
59
|
end
|
@@ -214,8 +214,6 @@ module RSpec
|
|
214
214
|
end
|
215
215
|
|
216
216
|
context "with a block" do
|
217
|
-
before { allow_unavoidable_1_8_deprecation }
|
218
|
-
|
219
217
|
it "stubs a method" do
|
220
218
|
klass.any_instance.stub(:foo) { 1 }
|
221
219
|
expect(klass.new.foo).to eq(1)
|
@@ -227,6 +225,24 @@ module RSpec
|
|
227
225
|
end
|
228
226
|
end
|
229
227
|
|
228
|
+
context "when partially mocking objects" do
|
229
|
+
let(:obj) { klass.new }
|
230
|
+
|
231
|
+
it "resets partially mocked objects correctly" do
|
232
|
+
allow_any_instance_of(klass).to receive(:existing_method).and_return("stubbed value")
|
233
|
+
|
234
|
+
# Simply resetting the proxy doesn't work
|
235
|
+
# what we need to have happen is
|
236
|
+
# ::RSpec::Mocks.any_instance_recorder_for(klass).stop_all_observation!
|
237
|
+
# but that is never invoked in ::
|
238
|
+
expect {
|
239
|
+
RSpec::Mocks.space.verify_all
|
240
|
+
}.to(
|
241
|
+
change { obj.existing_method }.from("stubbed value").to(:existing_method_return_value)
|
242
|
+
)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
230
246
|
context "core ruby objects" do
|
231
247
|
it "works uniformly across *everything*" do
|
232
248
|
Object.any_instance.stub(:foo).and_return(1)
|
@@ -267,22 +283,6 @@ module RSpec
|
|
267
283
|
end
|
268
284
|
end
|
269
285
|
|
270
|
-
context "with #stub!" do
|
271
|
-
it "raises with a message instructing the user to use stub instead" do
|
272
|
-
expect do
|
273
|
-
klass.any_instance.stub!(:foo)
|
274
|
-
end.to raise_error(/Use stub instead/)
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
context "with #unstub!" do
|
279
|
-
it "raises with a message instructing the user to use unstub instead" do
|
280
|
-
expect do
|
281
|
-
klass.any_instance.unstub!(:foo)
|
282
|
-
end.to raise_error(/Use unstub instead/)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
286
|
context "unstub implementation" do
|
287
287
|
it "replaces the stubbed method with the original method" do
|
288
288
|
klass.any_instance.stub(:existing_method)
|
@@ -377,7 +377,6 @@ module RSpec
|
|
377
377
|
klass.any_instance.should_not_receive(:bar)
|
378
378
|
klass.new.foo
|
379
379
|
RSpec::Mocks.space.verify_all
|
380
|
-
RSpec::Mocks.space.reset_all
|
381
380
|
end
|
382
381
|
end
|
383
382
|
|
@@ -400,36 +399,24 @@ module RSpec
|
|
400
399
|
|
401
400
|
it "fails if an instance is created but no invocation occurs" do
|
402
401
|
expect do
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
RSpec::Mocks.space.verify_all
|
407
|
-
ensure
|
408
|
-
RSpec::Mocks.space.reset_all
|
409
|
-
end
|
402
|
+
klass.any_instance.should_receive(:foo)
|
403
|
+
klass.new
|
404
|
+
RSpec::Mocks.space.verify_all
|
410
405
|
end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
|
411
406
|
end
|
412
407
|
|
413
408
|
it "fails if no instance is created" do
|
414
409
|
expect do
|
415
|
-
|
416
|
-
|
417
|
-
RSpec::Mocks.space.verify_all
|
418
|
-
ensure
|
419
|
-
RSpec::Mocks.space.reset_all
|
420
|
-
end
|
410
|
+
klass.any_instance.should_receive(:foo).and_return(1)
|
411
|
+
RSpec::Mocks.space.verify_all
|
421
412
|
end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
|
422
413
|
end
|
423
414
|
|
424
415
|
it "fails if no instance is created and there are multiple expectations" do
|
425
416
|
expect do
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
RSpec::Mocks.space.verify_all
|
430
|
-
ensure
|
431
|
-
RSpec::Mocks.space.reset_all
|
432
|
-
end
|
417
|
+
klass.any_instance.should_receive(:foo)
|
418
|
+
klass.any_instance.should_receive(:bar)
|
419
|
+
RSpec::Mocks.space.verify_all
|
433
420
|
end.to raise_error(RSpec::Mocks::MockExpectationError, 'Exactly one instance should have received the following message(s) but didn\'t: bar, foo')
|
434
421
|
end
|
435
422
|
|
@@ -491,36 +478,24 @@ module RSpec
|
|
491
478
|
|
492
479
|
it "fails if an instance is created but no invocation occurs" do
|
493
480
|
expect do
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
RSpec::Mocks.space.verify_all
|
498
|
-
ensure
|
499
|
-
RSpec::Mocks.space.reset_all
|
500
|
-
end
|
481
|
+
klass.any_instance.should_receive(:existing_method)
|
482
|
+
klass.new
|
483
|
+
RSpec::Mocks.space.verify_all
|
501
484
|
end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
|
502
485
|
end
|
503
486
|
|
504
487
|
it "fails if no instance is created" do
|
505
488
|
expect do
|
506
|
-
|
507
|
-
|
508
|
-
RSpec::Mocks.space.verify_all
|
509
|
-
ensure
|
510
|
-
RSpec::Mocks.space.reset_all
|
511
|
-
end
|
489
|
+
klass.any_instance.should_receive(:existing_method)
|
490
|
+
RSpec::Mocks.space.verify_all
|
512
491
|
end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
|
513
492
|
end
|
514
493
|
|
515
494
|
it "fails if no instance is created and there are multiple expectations" do
|
516
495
|
expect do
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
RSpec::Mocks.space.verify_all
|
521
|
-
ensure
|
522
|
-
RSpec::Mocks.space.reset_all
|
523
|
-
end
|
496
|
+
klass.any_instance.should_receive(:existing_method)
|
497
|
+
klass.any_instance.should_receive(:another_existing_method)
|
498
|
+
RSpec::Mocks.space.verify_all
|
524
499
|
end.to raise_error(RSpec::Mocks::MockExpectationError, 'Exactly one instance should have received the following message(s) but didn\'t: another_existing_method, existing_method')
|
525
500
|
end
|
526
501
|
|
@@ -613,24 +588,16 @@ module RSpec
|
|
613
588
|
|
614
589
|
it "fails when no instances are declared" do
|
615
590
|
expect do
|
616
|
-
|
617
|
-
|
618
|
-
RSpec::Mocks.space.verify_all
|
619
|
-
ensure
|
620
|
-
RSpec::Mocks.space.reset_all
|
621
|
-
end
|
591
|
+
klass.any_instance.should_receive(:foo).once
|
592
|
+
RSpec::Mocks.space.verify_all
|
622
593
|
end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
|
623
594
|
end
|
624
595
|
|
625
596
|
it "fails when an instance is declared but there are no invocations" do
|
626
597
|
expect do
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
RSpec::Mocks.space.verify_all
|
631
|
-
ensure
|
632
|
-
RSpec::Mocks.space.reset_all
|
633
|
-
end
|
598
|
+
klass.any_instance.should_receive(:foo).once
|
599
|
+
klass.new
|
600
|
+
RSpec::Mocks.space.verify_all
|
634
601
|
end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
|
635
602
|
end
|
636
603
|
|
@@ -755,55 +722,9 @@ module RSpec
|
|
755
722
|
|
756
723
|
it "fails when the other expecations are not met" do
|
757
724
|
expect do
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
RSpec::Mocks.space.verify_all
|
762
|
-
ensure
|
763
|
-
RSpec::Mocks.space.reset_all
|
764
|
-
end
|
765
|
-
end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
|
766
|
-
end
|
767
|
-
end
|
768
|
-
end
|
769
|
-
|
770
|
-
context "the 'any_number_of_times' constraint" do
|
771
|
-
it "passes for 0 invocations" do
|
772
|
-
klass.any_instance.should_receive(:foo).any_number_of_times
|
773
|
-
verify klass.new
|
774
|
-
end
|
775
|
-
|
776
|
-
it "passes for a non-zero number of invocations" do
|
777
|
-
allow(RSpec).to receive(:deprecate).with("any_number_of_times", :replacement => "stub")
|
778
|
-
|
779
|
-
klass.any_instance.should_receive(:foo).any_number_of_times
|
780
|
-
instance = klass.new
|
781
|
-
instance.foo
|
782
|
-
verify instance
|
783
|
-
end
|
784
|
-
|
785
|
-
it "does not interfere with other expectations" do
|
786
|
-
klass.any_instance.should_receive(:foo).any_number_of_times
|
787
|
-
klass.any_instance.should_receive(:existing_method).and_return(5)
|
788
|
-
expect(klass.new.existing_method).to eq(5)
|
789
|
-
end
|
790
|
-
|
791
|
-
context "when combined with other expectations" do
|
792
|
-
it "passes when the other expecations are met" do
|
793
|
-
klass.any_instance.should_receive(:foo).any_number_of_times
|
794
|
-
klass.any_instance.should_receive(:existing_method).and_return(5)
|
795
|
-
expect(klass.new.existing_method).to eq(5)
|
796
|
-
end
|
797
|
-
|
798
|
-
it "fails when the other expecations are not met" do
|
799
|
-
expect do
|
800
|
-
begin
|
801
|
-
klass.any_instance.should_receive(:foo).any_number_of_times
|
802
|
-
klass.any_instance.should_receive(:existing_method).and_return(5)
|
803
|
-
RSpec::Mocks.space.verify_all
|
804
|
-
ensure
|
805
|
-
RSpec::Mocks.space.reset_all
|
806
|
-
end
|
725
|
+
klass.any_instance.should_receive(:foo).never
|
726
|
+
klass.any_instance.should_receive(:existing_method).and_return(5)
|
727
|
+
RSpec::Mocks.space.verify_all
|
807
728
|
end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
|
808
729
|
end
|
809
730
|
end
|
@@ -823,14 +744,13 @@ module RSpec
|
|
823
744
|
context "public methods" do
|
824
745
|
before(:each) do
|
825
746
|
klass.any_instance.stub(:existing_method).and_return(1)
|
826
|
-
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to
|
747
|
+
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_truthy
|
827
748
|
end
|
828
749
|
|
829
750
|
it "restores the class to its original state after each example when no instance is created" do
|
830
751
|
space.verify_all
|
831
|
-
space.reset_all
|
832
752
|
|
833
|
-
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to
|
753
|
+
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
|
834
754
|
expect(klass.new.existing_method).to eq(existing_method_return_value)
|
835
755
|
end
|
836
756
|
|
@@ -838,9 +758,8 @@ module RSpec
|
|
838
758
|
klass.new.existing_method
|
839
759
|
|
840
760
|
space.verify_all
|
841
|
-
space.reset_all
|
842
761
|
|
843
|
-
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to
|
762
|
+
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
|
844
763
|
expect(klass.new.existing_method).to eq(existing_method_return_value)
|
845
764
|
end
|
846
765
|
|
@@ -849,9 +768,8 @@ module RSpec
|
|
849
768
|
klass.new.existing_method
|
850
769
|
|
851
770
|
space.verify_all
|
852
|
-
space.reset_all
|
853
771
|
|
854
|
-
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to
|
772
|
+
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
|
855
773
|
expect(klass.new.existing_method).to eq(existing_method_return_value)
|
856
774
|
end
|
857
775
|
end
|
@@ -860,15 +778,14 @@ module RSpec
|
|
860
778
|
before :each do
|
861
779
|
klass.any_instance.stub(:private_method).and_return(:something)
|
862
780
|
space.verify_all
|
863
|
-
space.reset_all
|
864
781
|
end
|
865
782
|
|
866
783
|
it "cleans up the backed up method" do
|
867
|
-
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to
|
784
|
+
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
|
868
785
|
end
|
869
786
|
|
870
787
|
it "restores a stubbed private method after the spec is run" do
|
871
|
-
expect(klass.private_method_defined?(:private_method)).to
|
788
|
+
expect(klass.private_method_defined?(:private_method)).to be_truthy
|
872
789
|
end
|
873
790
|
|
874
791
|
it "ensures that the restored method behaves as it originally did" do
|
@@ -883,15 +800,14 @@ module RSpec
|
|
883
800
|
klass.any_instance.should_receive(:private_method).and_return(:something)
|
884
801
|
klass.new.private_method
|
885
802
|
space.verify_all
|
886
|
-
space.reset_all
|
887
803
|
end
|
888
804
|
|
889
805
|
it "cleans up the backed up method" do
|
890
|
-
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to
|
806
|
+
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
|
891
807
|
end
|
892
808
|
|
893
809
|
it "restores a stubbed private method after the spec is run" do
|
894
|
-
expect(klass.private_method_defined?(:private_method)).to
|
810
|
+
expect(klass.private_method_defined?(:private_method)).to be_truthy
|
895
811
|
end
|
896
812
|
|
897
813
|
it "ensures that the restored method behaves as it originally did" do
|
@@ -931,7 +847,6 @@ module RSpec
|
|
931
847
|
klass.any_instance.should_receive(:existing_method).and_return(Object.new)
|
932
848
|
klass.new.existing_method
|
933
849
|
space.verify_all
|
934
|
-
space.reset_all
|
935
850
|
|
936
851
|
expect(klass.new.existing_method).to eq(existing_method_return_value)
|
937
852
|
end
|
@@ -944,7 +859,6 @@ module RSpec
|
|
944
859
|
klass.any_instance.stub(:existing_method).and_return(true)
|
945
860
|
|
946
861
|
RSpec::Mocks.space.verify_all
|
947
|
-
RSpec::Mocks.space.reset_all
|
948
862
|
expect(klass.new).to respond_to(:existing_method)
|
949
863
|
expect(klass.new.existing_method).to eq(existing_method_return_value)
|
950
864
|
end
|
@@ -1034,126 +948,6 @@ module RSpec
|
|
1034
948
|
end
|
1035
949
|
end
|
1036
950
|
end
|
1037
|
-
|
1038
|
-
context "by default" do
|
1039
|
-
def block_regex(line)
|
1040
|
-
/as the first block argument.*#{__FILE__}:#{line}/m
|
1041
|
-
end
|
1042
|
-
|
1043
|
-
it "is off" do
|
1044
|
-
expect(RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?).to be false
|
1045
|
-
end
|
1046
|
-
|
1047
|
-
it "will warn about allowances receiving blocks in 3.0" do
|
1048
|
-
klass = Struct.new(:bees)
|
1049
|
-
|
1050
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1051
|
-
allow_any_instance_of(klass).to receive(:foo) { |args| }
|
1052
|
-
klass.new(:faces).foo
|
1053
|
-
end
|
1054
|
-
|
1055
|
-
it "will warn about expectations receiving blocks in 3.0" do
|
1056
|
-
klass = Struct.new(:bees)
|
1057
|
-
|
1058
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1059
|
-
expect_any_instance_of(klass).to receive(:foo) { |args| }
|
1060
|
-
klass.new(:faces).foo
|
1061
|
-
end
|
1062
|
-
|
1063
|
-
it 'includes the line of the block declaration in the warning, ' +
|
1064
|
-
'even when it is different from the `any_instance` line', :unless => (RUBY_VERSION.to_f < 1.9) do
|
1065
|
-
klass = Class.new
|
1066
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 3))
|
1067
|
-
stub = klass.any_instance.stub(:foo)
|
1068
|
-
|
1069
|
-
stub.with("bar") { |args| }
|
1070
|
-
klass.new.foo("bar")
|
1071
|
-
end
|
1072
|
-
|
1073
|
-
it "will warn about expectations receiving blocks with a times restriction" do
|
1074
|
-
klass = Struct.new(:bees)
|
1075
|
-
|
1076
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1077
|
-
klass.any_instance.should_receive(:foo).exactly(3).times { |a| :some_return_value }
|
1078
|
-
|
1079
|
-
instance = klass.new(:faces)
|
1080
|
-
3.times { instance.foo }
|
1081
|
-
end
|
1082
|
-
|
1083
|
-
it "will warn about expectations receiving blocks with an argument expectation" do
|
1084
|
-
klass = Struct.new(:bees)
|
1085
|
-
|
1086
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1087
|
-
klass.any_instance.should_receive(:foo).with(3) { |b| :some_return_value }
|
1088
|
-
|
1089
|
-
instance = klass.new(:faces)
|
1090
|
-
instance.foo(3)
|
1091
|
-
end
|
1092
|
-
|
1093
|
-
it "works with a do end style block" do
|
1094
|
-
klass = Struct.new(:bees)
|
1095
|
-
|
1096
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1097
|
-
klass.any_instance.should_receive(:foo).with(3) do |a|
|
1098
|
-
:some_return_value
|
1099
|
-
end
|
1100
|
-
|
1101
|
-
instance = klass.new(:faces)
|
1102
|
-
instance.foo(3)
|
1103
|
-
end
|
1104
|
-
|
1105
|
-
it "won't warn if there is no implementation block on an expectation" do
|
1106
|
-
expect(RSpec).not_to receive(:warn_deprecation)
|
1107
|
-
|
1108
|
-
klass = Struct.new(:bees)
|
1109
|
-
|
1110
|
-
allow_any_instance_of(klass).to receive(:foo)
|
1111
|
-
klass.new(:faces).foo
|
1112
|
-
end
|
1113
|
-
|
1114
|
-
it "won't warn if the implementation block ignores arguments", :if => (RUBY_VERSION.to_f > 1.8) do
|
1115
|
-
expect(RSpec).not_to receive(:warn_deprecation)
|
1116
|
-
|
1117
|
-
klass = Struct.new(:bees)
|
1118
|
-
allow_any_instance_of(klass).to receive(:foo) { 5 }
|
1119
|
-
klass.new(:faces).foo
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
it "warns if the implementation block accepts a splat" do
|
1123
|
-
klass = Struct.new(:bees)
|
1124
|
-
|
1125
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1126
|
-
allow_any_instance_of(klass).to receive(:foo) { |*a| 5 }
|
1127
|
-
|
1128
|
-
klass.new(:faces).foo
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
it "warns if it the implementation is a lambda that expects no arguments" do
|
1132
|
-
klass = Struct.new(:bees)
|
1133
|
-
|
1134
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1135
|
-
allow_any_instance_of(klass).to receive(:foo, &lambda { 5 })
|
1136
|
-
|
1137
|
-
klass.new(:faces).foo
|
1138
|
-
end
|
1139
|
-
|
1140
|
-
it "will warn about stubs receiving blocks in 3.0" do
|
1141
|
-
klass = Struct.new(:bees)
|
1142
|
-
|
1143
|
-
expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
|
1144
|
-
expect_any_instance_of(klass).to receive(:foo) { |args| }
|
1145
|
-
klass.new(:faces).foo
|
1146
|
-
end
|
1147
|
-
|
1148
|
-
it "won't warn if there is no implementation block on an stub" do
|
1149
|
-
expect(RSpec).not_to receive(:warn_deprecation)
|
1150
|
-
|
1151
|
-
klass = Struct.new(:bees)
|
1152
|
-
|
1153
|
-
allow_any_instance_of(klass).to receive(:foo)
|
1154
|
-
klass.new(:faces).foo
|
1155
|
-
end
|
1156
|
-
end
|
1157
951
|
end
|
1158
952
|
|
1159
953
|
context 'when used in conjunction with a `dup`' do
|
@@ -1226,7 +1020,6 @@ module RSpec
|
|
1226
1020
|
expect(instance.existing_method).to eq :stubbed_return_value
|
1227
1021
|
|
1228
1022
|
RSpec::Mocks.verify
|
1229
|
-
RSpec::Mocks.teardown
|
1230
1023
|
|
1231
1024
|
expect(instance.existing_method).to eq :existing_method_return_value
|
1232
1025
|
end
|