rspec-mocks 2.10.0 → 2.11.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/Changelog.md +36 -1
- data/README.md +14 -2
- data/features/stubbing_constants/README.md +62 -0
- data/features/stubbing_constants/stub_defined_constant.feature +79 -0
- data/features/stubbing_constants/stub_undefined_constant.feature +50 -0
- data/lib/rspec/mocks/any_instance/chain.rb +0 -81
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +57 -0
- data/lib/rspec/mocks/any_instance/recorder.rb +6 -1
- data/lib/rspec/mocks/any_instance/stub_chain.rb +37 -0
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +25 -0
- data/lib/rspec/mocks/any_instance.rb +37 -1
- data/lib/rspec/mocks/argument_list_matcher.rb +93 -0
- data/lib/rspec/mocks/argument_matchers.rb +39 -31
- data/lib/rspec/mocks/error_generator.rb +7 -0
- data/lib/rspec/mocks/example_methods.rb +41 -0
- data/lib/rspec/mocks/framework.rb +2 -1
- data/lib/rspec/mocks/message_expectation.rb +27 -15
- data/lib/rspec/mocks/methods.rb +4 -0
- data/lib/rspec/mocks/proxy.rb +10 -4
- data/lib/rspec/mocks/stub_const.rb +280 -0
- data/lib/rspec/mocks/test_double.rb +3 -2
- data/lib/rspec/mocks/version.rb +1 -1
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
- data/spec/rspec/mocks/any_instance_spec.rb +66 -26
- data/spec/rspec/mocks/argument_expectation_spec.rb +7 -7
- data/spec/rspec/mocks/at_least_spec.rb +89 -50
- data/spec/rspec/mocks/block_return_value_spec.rb +8 -0
- data/spec/rspec/mocks/mock_spec.rb +261 -246
- data/spec/rspec/mocks/multiple_return_value_spec.rb +2 -2
- data/spec/rspec/mocks/null_object_mock_spec.rb +22 -0
- data/spec/rspec/mocks/stub_chain_spec.rb +47 -47
- data/spec/rspec/mocks/stub_const_spec.rb +309 -0
- data/spec/rspec/mocks/stub_spec.rb +2 -2
- data/spec/spec_helper.rb +3 -41
- metadata +18 -6
- data/lib/rspec/mocks/argument_expectation.rb +0 -52
|
@@ -75,10 +75,10 @@ module RSpec
|
|
|
75
75
|
context "when method is stubbed too" do
|
|
76
76
|
before { @double.stub(:do_something).and_return :stub_result }
|
|
77
77
|
|
|
78
|
-
it "uses the
|
|
78
|
+
it "uses the last value for subsequent calls" do
|
|
79
79
|
@double.do_something.should equal(11)
|
|
80
80
|
@double.do_something.should equal(22)
|
|
81
|
-
@double.do_something.should equal(
|
|
81
|
+
@double.do_something.should equal(22)
|
|
82
82
|
@double.rspec_verify
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -15,6 +15,15 @@ module RSpec
|
|
|
15
15
|
@double.stub(:foo)
|
|
16
16
|
@double.should respond_to(:foo)
|
|
17
17
|
end
|
|
18
|
+
|
|
19
|
+
it "raises an error when interpolated in a string as an integer" do
|
|
20
|
+
# Not sure why, but 1.9.2 raises a different error than 1.8.7 and 1.9.3...
|
|
21
|
+
expected_error = RUBY_VERSION == '1.9.2' ?
|
|
22
|
+
RSpec::Mocks::MockExpectationError :
|
|
23
|
+
TypeError
|
|
24
|
+
|
|
25
|
+
expect { "%i" % @double }.to raise_error(expected_error)
|
|
26
|
+
end
|
|
18
27
|
end
|
|
19
28
|
|
|
20
29
|
describe "a double acting as a null object" do
|
|
@@ -36,6 +45,11 @@ module RSpec
|
|
|
36
45
|
@double.something
|
|
37
46
|
end
|
|
38
47
|
|
|
48
|
+
it 'continues to return self from an explicit expectation' do
|
|
49
|
+
@double.should_receive(:bar)
|
|
50
|
+
@double.foo.bar.should be(@double)
|
|
51
|
+
end
|
|
52
|
+
|
|
39
53
|
it "fails verification when explicit exception not met" do
|
|
40
54
|
lambda do
|
|
41
55
|
@double.should_receive(:something)
|
|
@@ -59,6 +73,14 @@ module RSpec
|
|
|
59
73
|
@double.message(:expected_arg)
|
|
60
74
|
@double.message(:unexpected_arg)
|
|
61
75
|
end
|
|
76
|
+
|
|
77
|
+
it "can be interpolated in a string as an integer" do
|
|
78
|
+
# This form of string interpolation calls
|
|
79
|
+
# @double.to_int.to_int.to_int...etc until it gets an integer,
|
|
80
|
+
# and thus gets stuck in an infinite loop unless our double
|
|
81
|
+
# returns an int value from #to_int.
|
|
82
|
+
("%i" % @double).should eq("0")
|
|
83
|
+
end
|
|
62
84
|
end
|
|
63
85
|
|
|
64
86
|
describe "#as_null_object" do
|
|
@@ -3,27 +3,27 @@ require 'spec_helper'
|
|
|
3
3
|
module RSpec
|
|
4
4
|
module Mocks
|
|
5
5
|
describe "A chained method stub" do
|
|
6
|
-
|
|
6
|
+
let(:object) { Object.new }
|
|
7
7
|
|
|
8
8
|
context "with one method in chain" do
|
|
9
9
|
context "using and_return" do
|
|
10
10
|
it "returns expected value from chaining only one method call" do
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
object.stub_chain(:msg1).and_return(:return_value)
|
|
12
|
+
object.msg1.should equal(:return_value)
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
context "using a block" do
|
|
17
17
|
it "returns the correct value" do
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
object.stub_chain(:msg1) { :return_value }
|
|
19
|
+
object.msg1.should equal(:return_value)
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
context "using a hash" do
|
|
24
24
|
it "returns the value of the key/value pair" do
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
object.stub_chain(:msg1 => :return_value)
|
|
26
|
+
object.msg1.should equal(:return_value)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
|
@@ -31,22 +31,22 @@ module RSpec
|
|
|
31
31
|
context "with two methods in chain" do
|
|
32
32
|
context "using and_return" do
|
|
33
33
|
it "returns expected value from chaining two method calls" do
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
object.stub_chain(:msg1, :msg2).and_return(:return_value)
|
|
35
|
+
object.msg1.msg2.should equal(:return_value)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
context "using a block" do
|
|
40
40
|
it "returns the correct value" do
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
object.stub_chain(:msg1, :msg2) { :return_value }
|
|
42
|
+
object.msg1.msg2.should equal(:return_value)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
context "using a hash" do
|
|
47
47
|
it "returns the value of the key/value pair" do
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
object.stub_chain(:msg1, :msg2 => :return_value)
|
|
49
|
+
object.msg1.msg2.should equal(:return_value)
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -54,95 +54,95 @@ module RSpec
|
|
|
54
54
|
context "with four methods in chain" do
|
|
55
55
|
context "using and_return" do
|
|
56
56
|
it "returns expected value from chaining two method calls" do
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
object.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:return_value)
|
|
58
|
+
object.msg1.msg2.msg3.msg4.should equal(:return_value)
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
context "using a block" do
|
|
63
63
|
it "returns the correct value" do
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
object.stub_chain(:msg1, :msg2, :msg3, :msg4) { :return_value }
|
|
65
|
+
object.msg1.msg2.msg3.msg4.should equal(:return_value)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
context "using a hash" do
|
|
70
70
|
it "returns the value of the key/value pair" do
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
object.stub_chain(:msg1, :msg2, :msg3, :msg4 => :return_value)
|
|
72
|
+
object.msg1.msg2.msg3.msg4.should equal(:return_value)
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
context "using a hash with a string key" do
|
|
77
77
|
it "returns the value of the key/value pair" do
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
object.stub_chain("msg1.msg2.msg3.msg4" => :return_value)
|
|
79
|
+
object.msg1.msg2.msg3.msg4.should equal(:return_value)
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
it "returns expected value from chaining four method calls" do
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
object.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:return_value)
|
|
86
|
+
object.msg1.msg2.msg3.msg4.should equal(:return_value)
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
context "with messages shared across multiple chains" do
|
|
90
90
|
context "using and_return" do
|
|
91
91
|
context "starting with the same message" do
|
|
92
92
|
it "returns expected value" do
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
object.stub_chain(:msg1, :msg2, :msg3).and_return(:first)
|
|
94
|
+
object.stub_chain(:msg1, :msg2, :msg4).and_return(:second)
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
object.msg1.msg2.msg3.should equal(:first)
|
|
97
|
+
object.msg1.msg2.msg4.should equal(:second)
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
context "starting with the different messages" do
|
|
102
102
|
it "returns expected value" do
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
object.stub_chain(:msg1, :msg2, :msg3).and_return(:first)
|
|
104
|
+
object.stub_chain(:msg4, :msg2, :msg3).and_return(:second)
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
object.msg1.msg2.msg3.should equal(:first)
|
|
107
|
+
object.msg4.msg2.msg3.should equal(:second)
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
context "using => value" do
|
|
113
113
|
context "starting with the same message" do
|
|
114
|
-
it "returns expected value"
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
it "returns expected value" do
|
|
115
|
+
object.stub_chain(:msg1, :msg2, :msg3 => :first)
|
|
116
|
+
object.stub_chain(:msg1, :msg2, :msg4 => :second)
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
object.msg1.msg2.msg3.should equal(:first)
|
|
119
|
+
object.msg1.msg2.msg4.should equal(:second)
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
context "starting with different messages" do
|
|
124
|
-
it "returns expected value"
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
it "returns expected value" do
|
|
125
|
+
object.stub_chain(:msg1, :msg2, :msg3 => :first)
|
|
126
|
+
object.stub_chain(:msg4, :msg2, :msg3 => :second)
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
object.msg1.msg2.msg3.should equal(:first)
|
|
129
|
+
object.msg4.msg2.msg3.should equal(:second)
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
it "returns expected value when chain is a dot separated string, like stub_chain('msg1.msg2.msg3')" do
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
object.stub_chain("msg1.msg2.msg3").and_return(:return_value)
|
|
137
|
+
object.msg1.msg2.msg3.should equal(:return_value)
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
it "returns expected value from two chains with shared messages at the beginning" do
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
object.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:first)
|
|
142
|
+
object.stub_chain(:msg1, :msg2, :msg3, :msg5).and_return(:second)
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
object.msg1.msg2.msg3.msg4.should equal(:first)
|
|
145
|
+
object.msg1.msg2.msg3.msg5.should equal(:second)
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
end
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
TOP_LEVEL_VALUE_CONST = 7
|
|
4
|
+
|
|
5
|
+
class TestClass
|
|
6
|
+
M = :m
|
|
7
|
+
N = :n
|
|
8
|
+
|
|
9
|
+
class Nested
|
|
10
|
+
class NestedEvenMore
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module RSpec
|
|
16
|
+
module Mocks
|
|
17
|
+
describe "Constant Stubbing" do
|
|
18
|
+
include RSpec::Mocks::RecursiveConstMethods
|
|
19
|
+
|
|
20
|
+
def reset_rspec_mocks
|
|
21
|
+
::RSpec::Mocks.space.reset_all
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
shared_examples_for "loaded constant stubbing" do |const_name|
|
|
25
|
+
let!(:original_const_value) { const }
|
|
26
|
+
after { change_const_value_to(original_const_value) }
|
|
27
|
+
|
|
28
|
+
define_method :const do
|
|
29
|
+
recursive_const_get(const_name)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
define_method :parent_const do
|
|
33
|
+
recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
define_method :last_const_part do
|
|
37
|
+
const_name.split('::').last
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def change_const_value_to(value)
|
|
41
|
+
parent_const.send(:remove_const, last_const_part)
|
|
42
|
+
parent_const.const_set(last_const_part, value)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'allows it to be stubbed' do
|
|
46
|
+
const.should_not eq(7)
|
|
47
|
+
stub_const(const_name, 7)
|
|
48
|
+
const.should eq(7)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'resets it to its original value when rspec clears its mocks' do
|
|
52
|
+
original_value = const
|
|
53
|
+
original_value.should_not eq(:a)
|
|
54
|
+
stub_const(const_name, :a)
|
|
55
|
+
reset_rspec_mocks
|
|
56
|
+
const.should be(original_value)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns the stubbed value' do
|
|
60
|
+
orig_value = const
|
|
61
|
+
stub_const(const_name, 7).should eq(7)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
shared_examples_for "unloaded constant stubbing" do |const_name|
|
|
66
|
+
before { recursive_const_defined?(const_name).should be_false }
|
|
67
|
+
|
|
68
|
+
define_method :const do
|
|
69
|
+
recursive_const_get(const_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
define_method :parent_const do
|
|
73
|
+
recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
define_method :last_const_part do
|
|
77
|
+
const_name.split('::').last
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'allows it to be stubbed' do
|
|
81
|
+
stub_const(const_name, 7)
|
|
82
|
+
const.should eq(7)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'removes the constant when rspec clears its mocks' do
|
|
86
|
+
stub_const(const_name, 7)
|
|
87
|
+
reset_rspec_mocks
|
|
88
|
+
recursive_const_defined?(const_name).should be_false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'returns the stubbed value' do
|
|
92
|
+
stub_const(const_name, 7).should eq(7)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'ignores the :transfer_nested_constants option if passed' do
|
|
96
|
+
stub = Module.new
|
|
97
|
+
stub_const(const_name, stub, :transfer_nested_constants => true)
|
|
98
|
+
stub.constants.should eq([])
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "#stub_const" do
|
|
103
|
+
context 'for a loaded unnested constant' do
|
|
104
|
+
it_behaves_like "loaded constant stubbing", "TestClass"
|
|
105
|
+
|
|
106
|
+
it 'can be stubbed multiple times but still restores the original value properly' do
|
|
107
|
+
orig_value = TestClass
|
|
108
|
+
stub1, stub2 = Module.new, Module.new
|
|
109
|
+
stub_const("TestClass", stub1)
|
|
110
|
+
stub_const("TestClass", stub2)
|
|
111
|
+
|
|
112
|
+
reset_rspec_mocks
|
|
113
|
+
TestClass.should be(orig_value)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'allows nested constants to be transferred to a stub module' do
|
|
117
|
+
tc_nested = TestClass::Nested
|
|
118
|
+
stub = Module.new
|
|
119
|
+
stub_const("TestClass", stub, :transfer_nested_constants => true)
|
|
120
|
+
stub::M.should eq(:m)
|
|
121
|
+
stub::N.should eq(:n)
|
|
122
|
+
stub::Nested.should be(tc_nested)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'allows nested constants to be selectively transferred to a stub module' do
|
|
126
|
+
stub = Module.new
|
|
127
|
+
stub_const("TestClass", stub, :transfer_nested_constants => [:M, :N])
|
|
128
|
+
stub::M.should eq(:m)
|
|
129
|
+
stub::N.should eq(:n)
|
|
130
|
+
defined?(stub::Nested).should be_false
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'raises an error if asked to transfer nested constants but given an object that does not support them' do
|
|
134
|
+
original_tc = TestClass
|
|
135
|
+
stub = Object.new
|
|
136
|
+
expect {
|
|
137
|
+
stub_const("TestClass", stub, :transfer_nested_constants => true)
|
|
138
|
+
}.to raise_error(ArgumentError)
|
|
139
|
+
|
|
140
|
+
TestClass.should be(original_tc)
|
|
141
|
+
|
|
142
|
+
expect {
|
|
143
|
+
stub_const("TestClass", stub, :transfer_nested_constants => [:M])
|
|
144
|
+
}.to raise_error(ArgumentError)
|
|
145
|
+
|
|
146
|
+
TestClass.should be(original_tc)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'raises an error if asked to transfer nested constants on a constant that does not support nested constants' do
|
|
150
|
+
stub = Module.new
|
|
151
|
+
expect {
|
|
152
|
+
stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => true)
|
|
153
|
+
}.to raise_error(ArgumentError)
|
|
154
|
+
|
|
155
|
+
TOP_LEVEL_VALUE_CONST.should eq(7)
|
|
156
|
+
|
|
157
|
+
expect {
|
|
158
|
+
stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => [:M])
|
|
159
|
+
}.to raise_error(ArgumentError)
|
|
160
|
+
|
|
161
|
+
TOP_LEVEL_VALUE_CONST.should eq(7)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it 'raises an error if asked to transfer a nested constant that is not defined' do
|
|
165
|
+
original_tc = TestClass
|
|
166
|
+
defined?(TestClass::V).should be_false
|
|
167
|
+
stub = Module.new
|
|
168
|
+
|
|
169
|
+
expect {
|
|
170
|
+
stub_const("TestClass", stub, :transfer_nested_constants => [:V])
|
|
171
|
+
}.to raise_error(/cannot transfer nested constant.*V/i)
|
|
172
|
+
|
|
173
|
+
TestClass.should be(original_tc)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
context 'for a loaded nested constant' do
|
|
178
|
+
it_behaves_like "loaded constant stubbing", "TestClass::Nested"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
context 'for a loaded deeply nested constant' do
|
|
182
|
+
it_behaves_like "loaded constant stubbing", "TestClass::Nested::NestedEvenMore"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context 'for an unloaded unnested constant' do
|
|
186
|
+
it_behaves_like "unloaded constant stubbing", "X"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
context 'for an unloaded nested constant' do
|
|
190
|
+
it_behaves_like "unloaded constant stubbing", "X::Y"
|
|
191
|
+
|
|
192
|
+
it 'removes the root constant when rspec clears its mocks' do
|
|
193
|
+
defined?(X).should be_false
|
|
194
|
+
stub_const("X::Y", 7)
|
|
195
|
+
reset_rspec_mocks
|
|
196
|
+
defined?(X).should be_false
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
context 'for an unloaded deeply nested constant' do
|
|
201
|
+
it_behaves_like "unloaded constant stubbing", "X::Y::Z"
|
|
202
|
+
|
|
203
|
+
it 'removes the root constant when rspec clears its mocks' do
|
|
204
|
+
defined?(X).should be_false
|
|
205
|
+
stub_const("X::Y::Z", 7)
|
|
206
|
+
reset_rspec_mocks
|
|
207
|
+
defined?(X).should be_false
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
context 'for an unloaded constant nested within a loaded constant' do
|
|
212
|
+
it_behaves_like "unloaded constant stubbing", "TestClass::X"
|
|
213
|
+
|
|
214
|
+
it 'removes the unloaded constant but leaves the loaded constant when rspec resets its mocks' do
|
|
215
|
+
defined?(TestClass).should be_true
|
|
216
|
+
defined?(TestClass::X).should be_false
|
|
217
|
+
stub_const("TestClass::X", 7)
|
|
218
|
+
reset_rspec_mocks
|
|
219
|
+
defined?(TestClass).should be_true
|
|
220
|
+
defined?(TestClass::X).should be_false
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it 'raises a helpful error if it cannot be stubbed due to an intermediary constant that is not a module' do
|
|
224
|
+
TestClass::M.should be_a(Symbol)
|
|
225
|
+
expect { stub_const("TestClass::M::X", 5) }.to raise_error(/cannot stub/i)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
context 'for an unloaded constant nested deeply within a deeply nested loaded constant' do
|
|
230
|
+
it_behaves_like "unloaded constant stubbing", "TestClass::Nested::NestedEvenMore::X::Y::Z"
|
|
231
|
+
|
|
232
|
+
it 'removes the first unloaded constant but leaves the loaded nested constant when rspec resets its mocks' do
|
|
233
|
+
defined?(TestClass::Nested::NestedEvenMore).should be_true
|
|
234
|
+
defined?(TestClass::Nested::NestedEvenMore::X).should be_false
|
|
235
|
+
stub_const("TestClass::Nested::NestedEvenMore::X::Y::Z", 7)
|
|
236
|
+
reset_rspec_mocks
|
|
237
|
+
defined?(TestClass::Nested::NestedEvenMore).should be_true
|
|
238
|
+
defined?(TestClass::Nested::NestedEvenMore::X).should be_false
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
describe Constant do
|
|
245
|
+
describe ".original" do
|
|
246
|
+
context 'for a previously defined unstubbed constant' do
|
|
247
|
+
let(:const) { Constant.original("TestClass::M") }
|
|
248
|
+
|
|
249
|
+
it("exposes its name") { const.name.should eq("TestClass::M") }
|
|
250
|
+
it("indicates it was previously defined") { const.should be_previously_defined }
|
|
251
|
+
it("indicates it has not been stubbed") { const.should_not be_stubbed }
|
|
252
|
+
it("exposes its original value") { const.original_value.should eq(:m) }
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
context 'for a previously defined stubbed constant' do
|
|
256
|
+
before { stub_const("TestClass::M", :other) }
|
|
257
|
+
let(:const) { Constant.original("TestClass::M") }
|
|
258
|
+
|
|
259
|
+
it("exposes its name") { const.name.should eq("TestClass::M") }
|
|
260
|
+
it("indicates it was previously defined") { const.should be_previously_defined }
|
|
261
|
+
it("indicates it has been stubbed") { const.should be_stubbed }
|
|
262
|
+
it("exposes its original value") { const.original_value.should eq(:m) }
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
context 'for a previously undefined stubbed constant' do
|
|
266
|
+
before { stub_const("TestClass::Undefined", :other) }
|
|
267
|
+
let(:const) { Constant.original("TestClass::Undefined") }
|
|
268
|
+
|
|
269
|
+
it("exposes its name") { const.name.should eq("TestClass::Undefined") }
|
|
270
|
+
it("indicates it was not previously defined") { const.should_not be_previously_defined }
|
|
271
|
+
it("indicates it has been stubbed") { const.should be_stubbed }
|
|
272
|
+
it("returns nil for the original value") { const.original_value.should be_nil }
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
context 'for a previously undefined unstubbed constant' do
|
|
276
|
+
let(:const) { Constant.original("TestClass::Undefined") }
|
|
277
|
+
|
|
278
|
+
it("exposes its name") { const.name.should eq("TestClass::Undefined") }
|
|
279
|
+
it("indicates it was not previously defined") { const.should_not be_previously_defined }
|
|
280
|
+
it("indicates it has not been stubbed") { const.should_not be_stubbed }
|
|
281
|
+
it("returns nil for the original value") { const.original_value.should be_nil }
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
context 'for a previously defined constant that has been stubbed twice' do
|
|
285
|
+
before { stub_const("TestClass::M", 1) }
|
|
286
|
+
before { stub_const("TestClass::M", 2) }
|
|
287
|
+
let(:const) { Constant.original("TestClass::M") }
|
|
288
|
+
|
|
289
|
+
it("exposes its name") { const.name.should eq("TestClass::M") }
|
|
290
|
+
it("indicates it was previously defined") { const.should be_previously_defined }
|
|
291
|
+
it("indicates it has been stubbed") { const.should be_stubbed }
|
|
292
|
+
it("exposes its original value") { const.original_value.should eq(:m) }
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
context 'for a previously undefined constant that has been stubbed twice' do
|
|
296
|
+
before { stub_const("TestClass::Undefined", 1) }
|
|
297
|
+
before { stub_const("TestClass::Undefined", 2) }
|
|
298
|
+
let(:const) { Constant.original("TestClass::Undefined") }
|
|
299
|
+
|
|
300
|
+
it("exposes its name") { const.name.should eq("TestClass::Undefined") }
|
|
301
|
+
it("indicates it was not previously defined") { const.should_not be_previously_defined }
|
|
302
|
+
it("indicates it has been stubbed") { const.should be_stubbed }
|
|
303
|
+
it("returns nil for the original value") { const.original_value.should be_nil }
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
@@ -208,10 +208,10 @@ module RSpec
|
|
|
208
208
|
end.should raise_error(/received :foo with unexpected arguments/)
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
-
it "complains if called with other arg" do
|
|
211
|
+
it "complains if called with other arg", :github_issue => [123,147] do
|
|
212
212
|
lambda do
|
|
213
213
|
@stub.foo("other")
|
|
214
|
-
end.should raise_error(/received :foo with unexpected arguments/)
|
|
214
|
+
end.should raise_error(/received :foo with unexpected arguments.*Please stub a default value/m)
|
|
215
215
|
end
|
|
216
216
|
|
|
217
217
|
it "does not complain if also mocked w/ different args" do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
require 'rspec/core'
|
|
2
|
-
require 'rspec/mocks'
|
|
3
|
-
require 'rspec/expectations'
|
|
4
|
-
|
|
5
|
-
module Macros
|
|
6
|
-
def treats_method_missing_as_private(options = {:noop => true, :subject => nil})
|
|
7
|
-
it "has method_missing as private" do
|
|
8
|
-
self.class.describes.private_instance_methods.should include_method(:method_missing)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it "does not respond_to? method_missing (because it's private)" do
|
|
12
|
-
formatter = options[:subject] || described_class.new({ }, StringIO.new)
|
|
13
|
-
formatter.should_not respond_to(:method_missing)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
if options[:noop]
|
|
17
|
-
it "should respond_to? all messages" do
|
|
18
|
-
formatter = described_class.new({ }, StringIO.new)
|
|
19
|
-
formatter.should respond_to(:just_about_anything)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it "should respond_to? anything, when given the private flag" do
|
|
23
|
-
formatter = described_class.new({ }, StringIO.new)
|
|
24
|
-
formatter.respond_to?(:method_missing, true).should be_true
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
1
|
RSpec::Matchers.define :include_method do |expected|
|
|
31
2
|
match do |actual|
|
|
32
3
|
actual.map { |m| m.to_s }.include?(expected.to_s)
|
|
@@ -37,17 +8,8 @@ RSpec.configure do |config|
|
|
|
37
8
|
config.mock_with :rspec
|
|
38
9
|
config.color_enabled = true
|
|
39
10
|
config.order = :random
|
|
40
|
-
config.extend(Macros)
|
|
41
11
|
config.include(RSpec::Mocks::Methods)
|
|
42
|
-
|
|
43
|
-
config.
|
|
44
|
-
|
|
45
|
-
when "!jruby"
|
|
46
|
-
RUBY_ENGINE != "jruby"
|
|
47
|
-
when /^> (.*)/
|
|
48
|
-
!(RUBY_VERSION.to_s > $1)
|
|
49
|
-
else
|
|
50
|
-
!(RUBY_VERSION.to_s =~ /^#{version.to_s}/)
|
|
51
|
-
end
|
|
52
|
-
}
|
|
12
|
+
config.run_all_when_everything_filtered = true
|
|
13
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
14
|
+
config.filter_run_including :focus
|
|
53
15
|
end
|