spy 0.0.1 → 0.1.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/.yardopts +1 -0
- data/Gemfile +2 -0
- data/README.md +90 -44
- data/lib/spy.rb +85 -207
- data/lib/spy/agency.rb +65 -0
- data/lib/spy/constant.rb +67 -0
- data/lib/spy/core_ext/marshal.rb +28 -0
- data/lib/spy/double.rb +1 -1
- data/lib/spy/nest.rb +45 -0
- data/lib/spy/subroutine.rb +239 -0
- data/lib/spy/version.rb +2 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/spy/and_call_original_spec.rb +1 -1
- data/spec/spy/and_yield_spec.rb +23 -14
- data/spec/spy/hash_excluding_matcher_spec.rb +55 -59
- data/spec/spy/hash_including_matcher_spec.rb +69 -73
- data/spec/spy/mock_spec.rb +585 -589
- data/spec/spy/mutate_const_spec.rb +407 -367
- data/spec/spy/partial_mock_spec.rb +106 -162
- data/spec/spy/passing_argument_matchers_spec.rb +134 -136
- data/spec/spy/serialization_spec.rb +80 -74
- data/spec/spy/stub_implementation_spec.rb +14 -12
- data/spec/spy/stub_spec.rb +12 -12
- data/spec/spy/test_double_spec.rb +38 -41
- data/spy.gemspec +2 -1
- data/test/integration/test_constant_spying.rb +58 -0
- data/test/integration/test_subroutine_spying.rb +40 -0
- data/test/spy/test_double.rb +1 -1
- data/test/spy/test_subroutine.rb +191 -0
- data/test/support/pen.rb +50 -0
- data/test/test_helper.rb +4 -0
- metadata +33 -9
- data/TODO.md +0 -8
- data/lib/spy/dsl.rb +0 -7
- data/spec/spy/multiple_return_value_spec.rb +0 -119
- data/test/test_spy.rb +0 -258
@@ -1,196 +1,140 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
describe "using a Partial Mock," do
|
6
|
-
let(:object) { Object.new }
|
7
|
-
|
8
|
-
it "names the class in the failure message" do
|
9
|
-
object.should_receive(:foo)
|
10
|
-
expect do
|
11
|
-
object.rspec_verify
|
12
|
-
end.to raise_error(RSpec::Mocks::MockExpectationError, /\(#<Object:.*>\).foo/)
|
13
|
-
end
|
14
|
-
|
15
|
-
it "names the class in the failure message when expectation is on class" do
|
16
|
-
Object.should_receive(:foo)
|
17
|
-
expect {
|
18
|
-
Object.rspec_verify
|
19
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, /<Object \(class\)>/)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "does not conflict with @options in the object" do
|
23
|
-
object.instance_eval { @options = Object.new }
|
24
|
-
object.should_receive(:blah)
|
25
|
-
object.blah
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should_not_receive mocks out the method" do
|
29
|
-
object.should_not_receive(:fuhbar)
|
30
|
-
expect {
|
31
|
-
object.fuhbar
|
32
|
-
}.to raise_error(
|
33
|
-
RSpec::Mocks::MockExpectationError,
|
34
|
-
/expected\: 0 times\n received\: 1 time/
|
35
|
-
)
|
36
|
-
end
|
3
|
+
module Spy
|
4
|
+
describe "using a Partial Mock," do
|
37
5
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
it "should_receive mocks out the method" do
|
43
|
-
object.should_receive(:foobar).with(:test_param).and_return(1)
|
44
|
-
expect(object.foobar(:test_param)).to equal(1)
|
45
|
-
end
|
6
|
+
def stub(object, method_name)
|
7
|
+
Spy::Subroutine.new(object, method_name).hook(force: true)
|
8
|
+
end
|
46
9
|
|
47
|
-
|
48
|
-
object.should_receive(:foobar).with(:key => "value").and_return(1)
|
49
|
-
expect(object.foobar(:key => "value")).to equal(1)
|
50
|
-
end
|
10
|
+
let(:object) { Object.new }
|
51
11
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
12
|
+
it "names the class in the failure message" do
|
13
|
+
spy = stub(object, :foo)
|
14
|
+
expect(spy).to_not have_been_called
|
15
|
+
end
|
57
16
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
17
|
+
it "names the class in the failure message when expectation is on class" do
|
18
|
+
spy = stub(Object, :foo)
|
19
|
+
expect(spy).to_not have_been_called
|
20
|
+
end
|
62
21
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
22
|
+
it "does not conflict with @options in the object" do
|
23
|
+
object.instance_eval { @options = Object.new }
|
24
|
+
spy = stub(object, :blah)
|
25
|
+
object.blah
|
26
|
+
expect(spy).to have_been_called
|
27
|
+
end
|
69
28
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
29
|
+
it "should_receive mocks out the method" do
|
30
|
+
stub(object, :foobar).with(:test_param).and_return(1)
|
31
|
+
expect(object.foobar(:test_param)).to equal(1)
|
32
|
+
end
|
74
33
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
80
|
-
end
|
34
|
+
it "should_receive handles a hash" do
|
35
|
+
stub(object, :foobar).with(:key => "value").and_return(1)
|
36
|
+
expect(object.foobar(:key => "value")).to equal(1)
|
37
|
+
end
|
81
38
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
expect {
|
88
|
-
_nil.rspec_verify
|
89
|
-
}.to raise_error(
|
90
|
-
RSpec::Mocks::MockExpectationError,
|
91
|
-
%Q|(nil).foobar(any args)\n expected: 1 time\n received: 0 times|
|
92
|
-
)
|
93
|
-
end
|
39
|
+
it "should_receive handles an inner hash" do
|
40
|
+
hash = {:a => {:key => "value"}}
|
41
|
+
object.should_receive(:foobar).with(:key => "value").and_return(1)
|
42
|
+
expect(object.foobar(hash[:a])).to equal(1)
|
43
|
+
end
|
94
44
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
100
|
-
end
|
45
|
+
it "should_receive returns a message expectation" do
|
46
|
+
expect(object.should_receive(:foobar)).to be_kind_of(RSpec::Mocks::MessageExpectation)
|
47
|
+
object.foobar
|
48
|
+
end
|
101
49
|
|
102
|
-
|
103
|
-
|
50
|
+
it "should_receive verifies method was called" do
|
51
|
+
object.should_receive(:foobar).with(:test_param).and_return(1)
|
52
|
+
expect {
|
53
|
+
object.rspec_verify
|
54
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
55
|
+
end
|
104
56
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
57
|
+
it "should_receive also takes a String argument" do
|
58
|
+
object.should_receive('foobar')
|
59
|
+
object.foobar
|
109
60
|
end
|
110
61
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
62
|
+
it "should_not_receive also takes a String argument" do
|
63
|
+
object.should_not_receive('foobar')
|
64
|
+
expect {
|
65
|
+
object.foobar
|
66
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
67
|
+
end
|
117
68
|
|
118
|
-
|
119
|
-
|
120
|
-
|
69
|
+
it "uses reports nil in the error message" do
|
70
|
+
allow_message_expectations_on_nil
|
71
|
+
|
72
|
+
_nil = nil
|
73
|
+
_nil.should_receive(:foobar)
|
74
|
+
expect {
|
75
|
+
_nil.rspec_verify
|
76
|
+
}.to raise_error(
|
77
|
+
RSpec::Mocks::MockExpectationError,
|
78
|
+
%Q|(nil).foobar(any args)\n expected: 1 time\n received: 0 times|
|
79
|
+
)
|
80
|
+
end
|
121
81
|
|
122
|
-
|
123
|
-
|
124
|
-
|
82
|
+
it "includes the class name in the error when mocking a class method that is called an extra time with the wrong args" do
|
83
|
+
klass = Class.new do
|
84
|
+
def self.inspect
|
85
|
+
"MyClass"
|
125
86
|
end
|
126
87
|
end
|
127
88
|
|
128
|
-
|
89
|
+
klass.should_receive(:bar).with(1)
|
90
|
+
klass.bar(1)
|
129
91
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
92
|
+
expect {
|
93
|
+
klass.bar(2)
|
94
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, /MyClass/)
|
134
95
|
end
|
96
|
+
end
|
135
97
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
let(:klass) do
|
142
|
-
Class.new do
|
143
|
-
attr_reader :val
|
144
|
-
def initialize(val)
|
145
|
-
@val = val
|
146
|
-
end
|
147
|
-
|
148
|
-
def ==(other)
|
149
|
-
@val == other.val
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
it "does not raise an error when stubbing the object" do
|
155
|
-
o = klass.new :foo
|
156
|
-
expect { Spy.on(o, :bar) }.not_to raise_error(NoMethodError)
|
157
|
-
end
|
98
|
+
describe "Method visibility when using partial mocks" do
|
99
|
+
def stub(o, method_name)
|
100
|
+
Spy.on(o, method_name)
|
158
101
|
end
|
159
102
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
protected_method
|
166
|
-
end
|
167
|
-
protected
|
168
|
-
def protected_method; end
|
169
|
-
private
|
170
|
-
def private_method; end
|
103
|
+
let(:klass) do
|
104
|
+
Class.new do
|
105
|
+
def public_method
|
106
|
+
private_method
|
107
|
+
protected_method
|
171
108
|
end
|
109
|
+
protected
|
110
|
+
def protected_method; end
|
111
|
+
private
|
112
|
+
def private_method; end
|
172
113
|
end
|
114
|
+
end
|
173
115
|
|
174
|
-
|
175
|
-
|
176
|
-
it 'keeps public methods public' do
|
177
|
-
object.should_receive(:public_method)
|
178
|
-
expect(object.public_methods).to include_method(:public_method)
|
179
|
-
object.public_method
|
180
|
-
end
|
116
|
+
let(:object) { klass.new }
|
181
117
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
118
|
+
it 'keeps public methods public' do
|
119
|
+
spy = stub(object, :public_method)
|
120
|
+
expect(object.public_methods).to include_method(:public_method)
|
121
|
+
object.public_method
|
122
|
+
expect(spy).to have_been_called
|
123
|
+
end
|
187
124
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
125
|
+
it 'keeps private methods private' do
|
126
|
+
spy = stub(object, :private_method)
|
127
|
+
expect(object.private_methods).to include_method(:private_method)
|
128
|
+
object.public_method
|
129
|
+
expect(spy).to have_been_called
|
130
|
+
end
|
193
131
|
|
132
|
+
it 'keeps protected methods protected' do
|
133
|
+
spy = stub(object, :protected_method)
|
134
|
+
expect(object.protected_methods).to include_method(:protected_method)
|
135
|
+
object.public_method
|
136
|
+
expect(spy).to have_been_called
|
194
137
|
end
|
138
|
+
|
195
139
|
end
|
196
140
|
end
|
@@ -1,141 +1,139 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
@double.random_call(opts)
|
138
|
-
end
|
3
|
+
module Spy
|
4
|
+
describe "Matchers", :broken do
|
5
|
+
before(:each) do
|
6
|
+
@double = double('double')
|
7
|
+
Spy.on(Kernel, :warn)
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
@double.rspec_verify
|
12
|
+
end
|
13
|
+
|
14
|
+
context "handling argument matchers" do
|
15
|
+
it "accepts true as boolean()" do
|
16
|
+
@double.should_receive(:random_call).with(boolean())
|
17
|
+
@double.random_call(true)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "accepts false as boolean()" do
|
21
|
+
@double.should_receive(:random_call).with(boolean())
|
22
|
+
@double.random_call(false)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "accepts fixnum as kind_of(Numeric)" do
|
26
|
+
@double.should_receive(:random_call).with(kind_of(Numeric))
|
27
|
+
@double.random_call(1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "accepts float as an_instance_of(Numeric)" do
|
31
|
+
@double.should_receive(:random_call).with(kind_of(Numeric))
|
32
|
+
@double.random_call(1.5)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "accepts fixnum as instance_of(Fixnum)" do
|
36
|
+
@double.should_receive(:random_call).with(instance_of(Fixnum))
|
37
|
+
@double.random_call(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "does NOT accept fixnum as instance_of(Numeric)" do
|
41
|
+
@double.should_not_receive(:random_call).with(instance_of(Numeric))
|
42
|
+
@double.random_call(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does NOT accept float as instance_of(Numeric)" do
|
46
|
+
@double.should_not_receive(:random_call).with(instance_of(Numeric))
|
47
|
+
@double.random_call(1.5)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "accepts string as anything()" do
|
51
|
+
@double.should_receive(:random_call).with("a", anything(), "c")
|
52
|
+
@double.random_call("a", "whatever", "c")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "matches duck type with one method" do
|
56
|
+
@double.should_receive(:random_call).with(duck_type(:length))
|
57
|
+
@double.random_call([])
|
58
|
+
end
|
59
|
+
|
60
|
+
it "matches duck type with two methods" do
|
61
|
+
@double.should_receive(:random_call).with(duck_type(:abs, :div))
|
62
|
+
@double.random_call(1)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "matches no args against any_args()" do
|
66
|
+
@double.should_receive(:random_call).with(any_args)
|
67
|
+
@double.random_call()
|
68
|
+
end
|
69
|
+
|
70
|
+
it "matches one arg against any_args()" do
|
71
|
+
@double.should_receive(:random_call).with(any_args)
|
72
|
+
@double.random_call("a string")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "matches no args against no_args()" do
|
76
|
+
@double.should_receive(:random_call).with(no_args)
|
77
|
+
@double.random_call()
|
78
|
+
end
|
79
|
+
|
80
|
+
it "matches hash with hash_including same hash" do
|
81
|
+
@double.should_receive(:random_call).with(hash_including(:a => 1))
|
82
|
+
@double.random_call(:a => 1)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "handling block matchers" do
|
87
|
+
it "matches arguments against RSpec expectations" do
|
88
|
+
@double.should_receive(:random_call).with {|arg1, arg2, arr, *rest|
|
89
|
+
expect(arg1).to eq 5
|
90
|
+
expect(arg2).to have_at_least(3).characters
|
91
|
+
expect(arg2).to have_at_most(10).characters
|
92
|
+
expect(arr.map {|i| i * 2}).to eq [2,4,6]
|
93
|
+
expect(rest).to eq [:fee, "fi", 4]
|
94
|
+
}
|
95
|
+
@double.random_call 5, "hello", [1,2,3], :fee, "fi", 4
|
96
|
+
end
|
97
|
+
|
98
|
+
it "does not eval the block as the return value" do
|
99
|
+
eval_count = 0
|
100
|
+
@double.should_receive(:msg).with {|a| eval_count += 1}
|
101
|
+
@double.msg(:ignore)
|
102
|
+
expect(eval_count).to eq(1)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "handling non-matcher arguments" do
|
107
|
+
it "matches non special symbol (can be removed when deprecated symbols are removed)" do
|
108
|
+
@double.should_receive(:random_call).with(:some_symbol)
|
109
|
+
@double.random_call(:some_symbol)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "matches string against regexp" do
|
113
|
+
@double.should_receive(:random_call).with(/bcd/)
|
114
|
+
@double.random_call("abcde")
|
115
|
+
end
|
116
|
+
|
117
|
+
it "matches regexp against regexp" do
|
118
|
+
@double.should_receive(:random_call).with(/bcd/)
|
119
|
+
@double.random_call(/bcd/)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "matches against a hash submitted and received by value" do
|
123
|
+
@double.should_receive(:random_call).with(:a => "a", :b => "b")
|
124
|
+
@double.random_call(:a => "a", :b => "b")
|
125
|
+
end
|
126
|
+
|
127
|
+
it "matches against a hash submitted by reference and received by value" do
|
128
|
+
opts = {:a => "a", :b => "b"}
|
129
|
+
@double.should_receive(:random_call).with(opts)
|
130
|
+
@double.random_call(:a => "a", :b => "b")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "matches against a hash submitted by value and received by reference" do
|
134
|
+
opts = {:a => "a", :b => "b"}
|
135
|
+
@double.should_receive(:random_call).with(:a => "a", :b => "b")
|
136
|
+
@double.random_call(opts)
|
139
137
|
end
|
140
138
|
end
|
141
139
|
end
|