rspec-mocks 2.99.4 → 3.0.0.beta1
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.
- 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
|