rr 0.10.5 → 0.10.6
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/CHANGES +5 -0
- data/LICENSE +22 -0
- data/README.rdoc +4 -2
- data/VERSION.yml +2 -2
- data/lib/rr.rb +1 -0
- data/lib/rr/double_definitions/double_definition.rb +1 -1
- data/lib/rr/double_definitions/strategies/strategy.rb +1 -1
- data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +0 -1
- data/lib/rr/double_matches.rb +10 -19
- data/lib/rr/injections/double_injection.rb +13 -4
- data/lib/rr/method_dispatches/method_dispatch.rb +4 -3
- data/lib/rr/times_called_matchers/never_matcher.rb +23 -0
- data/spec/api/dont_allow/dont_allow_after_stub_spec.rb +14 -0
- data/spec/api/mock/mock_spec.rb +183 -0
- data/spec/api/proxy/proxy_spec.rb +86 -0
- data/spec/api/spy/spy_spec.rb +48 -0
- data/spec/api/strong/strong_spec.rb +87 -0
- data/spec/api/stub/stub_spec.rb +126 -0
- data/spec/rr/adapters/rr_methods_creator_spec.rb +1 -1
- data/spec/rr/double_definitions/double_definition_creator_spec.rb +1 -1
- metadata +10 -4
- data/spec/high_level_spec.rb +0 -398
data/CHANGES
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
- Added MIT license
|
2
|
+
- Fixed Bug - dont_allow doesn't work when it follows stub (http://github.com/btakita/rr/issues#issue/20)
|
3
|
+
- Fixed exception with DoubleInjections on proxy objects (http://github.com/btakita/rr/issues#issue/24)
|
4
|
+
- Fixed Bug - Can't stub attribute methods on a BelongsToAssociation (http://github.com/btakita/rr/issues#issue/24)
|
5
|
+
|
1
6
|
0.10.5
|
2
7
|
- Fixed issues with Ruby 1.9
|
3
8
|
- Fixed stack overflow caused by double include in Test::Unit adapter [http://github.com/btakita/rr/issues#issue/16]. Identified by Dave Myron (http://github.com/contentfree)
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2010 Brian Takita
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -327,8 +327,8 @@ RR::WildcardMatchers for details.
|
|
327
327
|
mock(object).method_name(anything).times(any_times) {return_value}
|
328
328
|
|
329
329
|
== Special Thanks To
|
330
|
-
With any development effort, there are countless people who have contributed
|
331
|
-
to
|
330
|
+
With any development effort, there are countless people who have contributed to making it possible. We all are standing on the shoulders of giants.
|
331
|
+
If you have directly contributed to RR and I missed you in this list, please let me know and I will add you. Thanks!
|
332
332
|
* Andreas Haller for patches
|
333
333
|
* Aslak Hellesoy for Developing Rspec
|
334
334
|
* Bryan Helmkamp for patches
|
@@ -347,9 +347,11 @@ to making it possible. We all are standing on the shoulders of giants.
|
|
347
347
|
* Matthew O'Connor for patches and pairing with me
|
348
348
|
* Michael Niessner for patches and pairing with me
|
349
349
|
* Mike Mangino (from Elevated Rails) for patches and pairing with me
|
350
|
+
* Myron Marston for bug reports
|
350
351
|
* Nick Kallen for documentation suggestions, bug reports, and patches
|
351
352
|
* Nathan Sobo for various ideas and inspiration for cleaner and more expressive code
|
352
353
|
* Parker Thompson for pairing with me
|
353
354
|
* Phil Darnowsky for patches
|
354
355
|
* Pivotal Labs for sponsoring RR development
|
355
356
|
* Stephen Baker for Developing Rspec
|
357
|
+
* Tatsuya Ono for patches
|
data/VERSION.yml
CHANGED
data/lib/rr.rb
CHANGED
@@ -64,6 +64,7 @@ require "#{dir}/rr/wildcard_matchers/hash_including"
|
|
64
64
|
require "#{dir}/rr/times_called_matchers/terminal"
|
65
65
|
require "#{dir}/rr/times_called_matchers/non_terminal"
|
66
66
|
require "#{dir}/rr/times_called_matchers/times_called_matcher"
|
67
|
+
require "#{dir}/rr/times_called_matchers/never_matcher"
|
67
68
|
require "#{dir}/rr/times_called_matchers/any_times_matcher"
|
68
69
|
require "#{dir}/rr/times_called_matchers/integer_matcher"
|
69
70
|
require "#{dir}/rr/times_called_matchers/range_matcher"
|
data/lib/rr/double_matches.rb
CHANGED
@@ -19,33 +19,24 @@ module RR
|
|
19
19
|
if double.exact_match?(*args)
|
20
20
|
matching_doubles << double
|
21
21
|
if double.attempt?
|
22
|
-
|
22
|
+
if double.terminal?
|
23
|
+
exact_terminal_doubles_to_attempt << double
|
24
|
+
else
|
25
|
+
exact_non_terminal_doubles_to_attempt << double
|
26
|
+
end
|
23
27
|
end
|
24
28
|
elsif double.wildcard_match?(*args)
|
25
29
|
matching_doubles << double
|
26
30
|
if double.attempt?
|
27
|
-
|
31
|
+
if double.terminal?
|
32
|
+
wildcard_terminal_doubles_to_attempt << double
|
33
|
+
else
|
34
|
+
wildcard_non_terminal_doubles_to_attempt << double
|
35
|
+
end
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
31
39
|
self
|
32
40
|
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
def exact_double_is_terminal_or_non_terminal(double)
|
36
|
-
if double.terminal?
|
37
|
-
exact_terminal_doubles_to_attempt << double
|
38
|
-
else
|
39
|
-
exact_non_terminal_doubles_to_attempt << double
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def wildcard_double_is_terminal_or_non_terminal(double)
|
44
|
-
if double.terminal?
|
45
|
-
wildcard_terminal_doubles_to_attempt << double
|
46
|
-
else
|
47
|
-
wildcard_non_terminal_doubles_to_attempt << double
|
48
|
-
end
|
49
|
-
end
|
50
41
|
end
|
51
42
|
end
|
@@ -28,7 +28,11 @@ module RR
|
|
28
28
|
def bind
|
29
29
|
if subject_respond_to_method?(method_name)
|
30
30
|
if subject_has_method_defined?(method_name)
|
31
|
-
|
31
|
+
if subject_is_proxy_for_method?(method_name)
|
32
|
+
bind_method
|
33
|
+
else
|
34
|
+
bind_method_with_alias
|
35
|
+
end
|
32
36
|
else
|
33
37
|
space.method_missing_injection(subject)
|
34
38
|
space.singleton_method_added_injection(subject)
|
@@ -95,6 +99,11 @@ module RR
|
|
95
99
|
end
|
96
100
|
|
97
101
|
protected
|
102
|
+
def subject_is_proxy_for_method?(method_name)
|
103
|
+
method_owner = @subject.method(method_name).owner
|
104
|
+
!(subject_class.object_id == method_owner.object_id || subject_class.ancestors.include?(method_owner))
|
105
|
+
end
|
106
|
+
|
98
107
|
def deferred_bind_method
|
99
108
|
unless subject_has_method_defined?(original_method_alias_name)
|
100
109
|
bind_method_with_alias
|
@@ -108,13 +117,13 @@ module RR
|
|
108
117
|
end
|
109
118
|
|
110
119
|
def bind_method
|
111
|
-
|
120
|
+
subject = @subject.is_a?(Class) && !@subject.name.empty? ? @subject.name : "self"
|
121
|
+
subject_class.class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
|
112
122
|
def #{@method_name}(*args, &block)
|
113
123
|
arguments = MethodArguments.new(args, block)
|
114
|
-
RR::Space.double_injection(
|
124
|
+
RR::Space.double_injection(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
|
115
125
|
end
|
116
126
|
METHOD
|
117
|
-
subject_class.class_eval(returns_method, __FILE__, __LINE__ - 5)
|
118
127
|
end
|
119
128
|
end
|
120
129
|
end
|
@@ -12,11 +12,12 @@ module RR
|
|
12
12
|
if double
|
13
13
|
double.method_call(args)
|
14
14
|
call_yields
|
15
|
-
|
15
|
+
return_value_1 = call_implementation
|
16
|
+
return_value_2 = extract_subject_from_return_value(return_value_1)
|
16
17
|
if after_call_proc
|
17
|
-
extract_subject_from_return_value(after_call_proc.call(
|
18
|
+
extract_subject_from_return_value(after_call_proc.call(return_value_2))
|
18
19
|
else
|
19
|
-
|
20
|
+
return_value_2
|
20
21
|
end
|
21
22
|
else
|
22
23
|
double_not_found_error
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RR
|
2
|
+
module TimesCalledMatchers #:nodoc:
|
3
|
+
class NeverMatcher < TimesCalledMatcher
|
4
|
+
include Terminal
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def possible_match?(times_called)
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def matches?(times_called)
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def attempt?(times_called)
|
19
|
+
raise RR::Errors::TimesCalledError, error_message(1)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
|
3
|
+
describe "dont_allow called after stub" do
|
4
|
+
context "when the subject method is called" do
|
5
|
+
it "raises a TimesCalledError" do
|
6
|
+
subject = Object.new
|
7
|
+
stub(subject).foobar
|
8
|
+
dont_allow(subject).foobar
|
9
|
+
lambda do
|
10
|
+
subject.foobar
|
11
|
+
end.should raise_error(RR::Errors::TimesCalledError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
|
3
|
+
describe "mock" do
|
4
|
+
attr_reader :subject
|
5
|
+
before(:each) do
|
6
|
+
@subject = Object.new
|
7
|
+
extend RR::Adapters::RRMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
RR.reset
|
12
|
+
end
|
13
|
+
|
14
|
+
it "mocks via inline call" do
|
15
|
+
mock(subject).to_s {"a value"}
|
16
|
+
subject.to_s.should == "a value"
|
17
|
+
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ".once.ordered" do
|
21
|
+
it "returns the values in the ordered called" do
|
22
|
+
mock(subject).to_s {"value 1"}.ordered
|
23
|
+
mock(subject).to_s {"value 2"}.twice
|
24
|
+
subject.to_s.should == "value 1"
|
25
|
+
subject.to_s.should == "value 2"
|
26
|
+
subject.to_s.should == "value 2"
|
27
|
+
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the subject is a proxy for the object with the defined method" do
|
32
|
+
it "stubs the method on the proxy object" do
|
33
|
+
proxy_target = Class.new {def foobar; :original_foobar; end}.new
|
34
|
+
proxy = Class.new do
|
35
|
+
def initialize(target)
|
36
|
+
@target = target
|
37
|
+
end
|
38
|
+
|
39
|
+
instance_methods.each do |m|
|
40
|
+
unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == 'method_missing'
|
41
|
+
alias_method "__blank_slated_#{m}", m
|
42
|
+
undef_method m
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(method_name, *args, &block)
|
47
|
+
@target.send(method_name, *args, &block)
|
48
|
+
end
|
49
|
+
end.new(proxy_target)
|
50
|
+
proxy.methods.should =~ proxy_target.methods
|
51
|
+
|
52
|
+
mock(proxy).foobar {:new_foobar}
|
53
|
+
proxy.foobar.should == :new_foobar
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'allows terse chaining' do
|
58
|
+
mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}}
|
59
|
+
subject.first(1).second(2).third(3).should == 4
|
60
|
+
|
61
|
+
mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}}
|
62
|
+
subject.first(1).second(2).third(3).should == 4
|
63
|
+
|
64
|
+
mock(subject).first(1) {mock!.second(2).mock!.third(3) {4}}
|
65
|
+
subject.first(1).second(2).third(3).should == 4
|
66
|
+
|
67
|
+
mock(subject).first(1) {mock!.second(2).mock! {third(3) {4}}}
|
68
|
+
subject.first(1).second(2).third(3).should == 4
|
69
|
+
|
70
|
+
mock(subject).first(1).mock!.second(2).mock!.third(3) {4}
|
71
|
+
subject.first(1).second(2).third(3).should == 4
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'allows chaining with proxy' do
|
75
|
+
find_return_value = Object.new
|
76
|
+
def find_return_value.child
|
77
|
+
:the_child
|
78
|
+
end
|
79
|
+
(class << subject; self; end).class_eval do
|
80
|
+
define_method(:find) do |id|
|
81
|
+
id == '1' ? find_return_value : raise(ArgumentError)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
mock.proxy(subject).find('1').mock.proxy!.child
|
86
|
+
subject.find('1').child.should == :the_child
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'allows branched chaining' do
|
90
|
+
mock(subject).first do
|
91
|
+
mock! do |expect|
|
92
|
+
expect.branch1 {mock!.branch11 {11}}
|
93
|
+
expect.branch2 {mock!.branch22 {22}}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
o = subject.first
|
97
|
+
o.branch1.branch11.should == 11
|
98
|
+
o.branch2.branch22.should == 22
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'allows chained ordering' do
|
102
|
+
mock(subject).to_s {"value 1"}.then.to_s {"value 2"}.twice.then.to_s {"value 3"}.once
|
103
|
+
subject.to_s.should == "value 1"
|
104
|
+
subject.to_s.should == "value 2"
|
105
|
+
subject.to_s.should == "value 2"
|
106
|
+
subject.to_s.should == "value 3"
|
107
|
+
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "mocks via block with argument" do
|
111
|
+
mock subject do |c|
|
112
|
+
c.to_s {"a value"}
|
113
|
+
c.to_sym {:crazy}
|
114
|
+
end
|
115
|
+
subject.to_s.should == "a value"
|
116
|
+
subject.to_sym.should == :crazy
|
117
|
+
end
|
118
|
+
|
119
|
+
it "mocks via block without argument" do
|
120
|
+
mock subject do
|
121
|
+
to_s {"a value"}
|
122
|
+
to_sym {:crazy}
|
123
|
+
end
|
124
|
+
subject.to_s.should == "a value"
|
125
|
+
subject.to_sym.should == :crazy
|
126
|
+
end
|
127
|
+
|
128
|
+
it "has wildcard matchers" do
|
129
|
+
mock(subject).foobar(
|
130
|
+
is_a(String),
|
131
|
+
anything,
|
132
|
+
numeric,
|
133
|
+
boolean,
|
134
|
+
duck_type(:to_s),
|
135
|
+
/abc/
|
136
|
+
) {"value 1"}.twice
|
137
|
+
subject.foobar(
|
138
|
+
'hello',
|
139
|
+
Object.new,
|
140
|
+
99,
|
141
|
+
false,
|
142
|
+
"My String",
|
143
|
+
"Tabcola"
|
144
|
+
).should == "value 1"
|
145
|
+
lambda do
|
146
|
+
subject.foobar(:failure)
|
147
|
+
end.should raise_error( RR::Errors::DoubleNotFoundError )
|
148
|
+
end
|
149
|
+
|
150
|
+
it "mocks methods without letters" do
|
151
|
+
mock(subject) == 55
|
152
|
+
|
153
|
+
subject == 55
|
154
|
+
lambda do
|
155
|
+
subject == 99
|
156
|
+
end.should raise_error(RR::Errors::DoubleNotFoundError)
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "on class method" do
|
160
|
+
class SampleClass1
|
161
|
+
def self.hello; "hello!"; end
|
162
|
+
end
|
163
|
+
|
164
|
+
class SampleClass2 < SampleClass1; end
|
165
|
+
|
166
|
+
it "can mock" do
|
167
|
+
mock(SampleClass1).hello { "hola!" }
|
168
|
+
|
169
|
+
SampleClass1.hello.should == "hola!"
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should not break when it is mocked on subclass" do
|
173
|
+
mock(SampleClass1).hello { "hi!" }
|
174
|
+
|
175
|
+
SampleClass2.hello.should == "hi!"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should not get affected from a previous example" do
|
179
|
+
SampleClass2.hello.should == "hello!"
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
|
3
|
+
describe "proxy" do
|
4
|
+
attr_reader :subject
|
5
|
+
before(:each) do
|
6
|
+
@subject = Object.new
|
7
|
+
extend RR::Adapters::RRMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
RR.reset
|
12
|
+
end
|
13
|
+
|
14
|
+
it "proxies via inline call" do
|
15
|
+
expected_to_s_value = subject.to_s
|
16
|
+
mock.proxy(subject).to_s
|
17
|
+
subject.to_s.should == expected_to_s_value
|
18
|
+
lambda {subject.to_s}.should raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "proxy allows ordering" do
|
22
|
+
def subject.to_s(arg)
|
23
|
+
"Original to_s with arg #{arg}"
|
24
|
+
end
|
25
|
+
mock.proxy(subject).to_s(:foo).ordered
|
26
|
+
mock.proxy(subject).to_s(:bar).twice.ordered
|
27
|
+
|
28
|
+
subject.to_s(:foo).should == "Original to_s with arg foo"
|
29
|
+
subject.to_s(:bar).should == "Original to_s with arg bar"
|
30
|
+
subject.to_s(:bar).should == "Original to_s with arg bar"
|
31
|
+
lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "proxy allows ordering" do
|
35
|
+
def subject.to_s(arg)
|
36
|
+
"Original to_s with arg #{arg}"
|
37
|
+
end
|
38
|
+
mock.proxy(subject).to_s(:foo).ordered
|
39
|
+
mock.proxy(subject).to_s(:bar).twice.ordered
|
40
|
+
|
41
|
+
subject.to_s(:foo).should == "Original to_s with arg foo"
|
42
|
+
subject.to_s(:bar).should == "Original to_s with arg bar"
|
43
|
+
subject.to_s(:bar).should == "Original to_s with arg bar"
|
44
|
+
lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "proxies via block with argument" do
|
48
|
+
def subject.foobar_1(*args)
|
49
|
+
:original_value_1
|
50
|
+
end
|
51
|
+
|
52
|
+
def subject.foobar_2
|
53
|
+
:original_value_2
|
54
|
+
end
|
55
|
+
|
56
|
+
mock.proxy subject do |c|
|
57
|
+
c.foobar_1(1)
|
58
|
+
c.foobar_2
|
59
|
+
end
|
60
|
+
subject.foobar_1(1).should == :original_value_1
|
61
|
+
lambda {subject.foobar_1(:blah)}.should raise_error
|
62
|
+
|
63
|
+
subject.foobar_2.should == :original_value_2
|
64
|
+
lambda {subject.foobar_2(:blah)}.should raise_error
|
65
|
+
end
|
66
|
+
|
67
|
+
it "proxies via block without argument" do
|
68
|
+
def subject.foobar_1(*args)
|
69
|
+
:original_value_1
|
70
|
+
end
|
71
|
+
|
72
|
+
def subject.foobar_2
|
73
|
+
:original_value_2
|
74
|
+
end
|
75
|
+
|
76
|
+
mock.proxy subject do
|
77
|
+
foobar_1(1)
|
78
|
+
foobar_2
|
79
|
+
end
|
80
|
+
subject.foobar_1(1).should == :original_value_1
|
81
|
+
lambda {subject.foobar_1(:blah)}.should raise_error
|
82
|
+
|
83
|
+
subject.foobar_2.should == :original_value_2
|
84
|
+
lambda {subject.foobar_2(:blah)}.should raise_error
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
|
3
|
+
describe "spy" do
|
4
|
+
attr_reader :subject
|
5
|
+
before(:each) do
|
6
|
+
@subject = Object.new
|
7
|
+
extend RR::Adapters::RRMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
RR.reset
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should record all method invocations" do
|
15
|
+
subject = Object.new
|
16
|
+
def subject.something
|
17
|
+
end
|
18
|
+
|
19
|
+
def subject.something_else
|
20
|
+
end
|
21
|
+
|
22
|
+
spy(subject)
|
23
|
+
|
24
|
+
subject.something
|
25
|
+
subject.something_else
|
26
|
+
subject.to_s
|
27
|
+
|
28
|
+
received(subject).something.call
|
29
|
+
received(subject).something_else.call
|
30
|
+
received(subject).to_s.call
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "RR recorded_calls" do
|
34
|
+
it "should verify method calls after the fact" do
|
35
|
+
stub(subject).pig_rabbit
|
36
|
+
subject.pig_rabbit("bacon", "bunny meat")
|
37
|
+
#subject.should have_received.pig_rabitt("bacon", "bunny meat")
|
38
|
+
received(subject).pig_rabbit("bacon", "bunny meat").call
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should verify method calls after the fact" do
|
42
|
+
stub(subject).pig_rabbit
|
43
|
+
lambda do
|
44
|
+
received(subject).pig_rabbit("bacon", "bunny meat").call
|
45
|
+
end.should raise_error(RR::Errors::SpyVerificationErrors::SpyVerificationError)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
|
3
|
+
class StrongSpecFixture
|
4
|
+
def method_with_no_arguments
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_with_one_argument(string)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_with_two_arguments(string, integer)
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_with_three_arguments_including_varargs(string, integer, *args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_with_varargs(*args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "strong" do
|
21
|
+
attr_reader :subject
|
22
|
+
before(:each) do
|
23
|
+
@subject = Object.new
|
24
|
+
extend RR::Adapters::RRMethods
|
25
|
+
end
|
26
|
+
|
27
|
+
after(:each) do
|
28
|
+
RR.reset
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the method does not exist" do
|
32
|
+
it "raises an exception" do
|
33
|
+
lambda do
|
34
|
+
strong.stub(StrongSpecFixture.new).something
|
35
|
+
end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when the method exists with no arguments" do
|
40
|
+
it "does not raise an exception" do
|
41
|
+
strong.stub(StrongSpecFixture.new).method_with_no_arguments
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when the method has a different arity" do
|
46
|
+
it "raises an exception" do
|
47
|
+
lambda do
|
48
|
+
strong.stub(StrongSpecFixture.new).method_with_one_argument
|
49
|
+
end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the method has accepts a variable number of arguments" do
|
54
|
+
it "does not raise an exception" do
|
55
|
+
strong.stub(StrongSpecFixture.new).method_with_varargs
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when the method does not provide the required parameters before varargs" do
|
60
|
+
it "raises an exception" do
|
61
|
+
lambda do
|
62
|
+
strong.stub(StrongSpecFixture.new).method_with_three_arguments_including_varargs
|
63
|
+
end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the minimum number of parameters are provided" do
|
68
|
+
it "does not raise an exception" do
|
69
|
+
strong.stub(StrongSpecFixture.new).method_with_three_arguments_including_varargs("one", 2)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when using instance_of and the method does not exist" do
|
74
|
+
it "raises an exception" do
|
75
|
+
lambda do
|
76
|
+
strong.stub.instance_of(StrongSpecFixture).something
|
77
|
+
StrongSpecFixture.new
|
78
|
+
end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when using instance_of and the method does exist" do
|
83
|
+
it "does not raise an exception" do
|
84
|
+
strong.stub.instance_of(StrongSpecFixture).method_with_no_arguments
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
|
3
|
+
class StubSpecFixture
|
4
|
+
attr_reader :initialize_arguments
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
@initialize_arguments = args
|
8
|
+
yield if block_given?
|
9
|
+
method_run_in_initialize
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_run_in_initialize
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "stub" do
|
18
|
+
attr_reader :subject
|
19
|
+
before(:each) do
|
20
|
+
@subject = Object.new
|
21
|
+
extend RR::Adapters::RRMethods
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:each) do
|
25
|
+
RR.reset
|
26
|
+
end
|
27
|
+
|
28
|
+
it "stubs via inline call" do
|
29
|
+
stub(subject).to_s {"a value"}
|
30
|
+
subject.to_s.should == "a value"
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".once.ordered" do
|
34
|
+
it "returns the values in the ordered called" do
|
35
|
+
stub(subject).to_s {"value 1"}.once.ordered
|
36
|
+
stub(subject).to_s {"value 2"}.once.ordered
|
37
|
+
|
38
|
+
subject.to_s.should == "value 1"
|
39
|
+
subject.to_s.should == "value 2"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when the subject is a proxy for the object with the defined method" do
|
44
|
+
it "stubs the method on the proxy object" do
|
45
|
+
proxy_target = Class.new {def foobar; :original_foobar; end}.new
|
46
|
+
proxy = Class.new do
|
47
|
+
def initialize(target)
|
48
|
+
@target = target
|
49
|
+
end
|
50
|
+
|
51
|
+
instance_methods.each do |m|
|
52
|
+
unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == 'method_missing'
|
53
|
+
alias_method "__blank_slated_#{m}", m
|
54
|
+
undef_method m
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(method_name, *args, &block)
|
59
|
+
@target.send(method_name, *args, &block)
|
60
|
+
end
|
61
|
+
end.new(proxy_target)
|
62
|
+
proxy.methods.should =~ proxy_target.methods
|
63
|
+
|
64
|
+
stub(proxy).foobar {:new_foobar}
|
65
|
+
proxy.foobar.should == :new_foobar
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "stubs via block with argument" do
|
70
|
+
stub subject do |d|
|
71
|
+
d.to_s {"a value"}
|
72
|
+
d.to_sym {:crazy}
|
73
|
+
end
|
74
|
+
subject.to_s.should == "a value"
|
75
|
+
subject.to_sym.should == :crazy
|
76
|
+
end
|
77
|
+
|
78
|
+
it "stubs via block without argument" do
|
79
|
+
stub subject do
|
80
|
+
to_s {"a value"}
|
81
|
+
to_sym {:crazy}
|
82
|
+
end
|
83
|
+
subject.to_s.should == "a value"
|
84
|
+
subject.to_sym.should == :crazy
|
85
|
+
end
|
86
|
+
|
87
|
+
it "stubs instance_of" do
|
88
|
+
stub.instance_of(StubSpecFixture) do |o|
|
89
|
+
o.to_s {"High Level Spec"}
|
90
|
+
end
|
91
|
+
StubSpecFixture.new.to_s.should == "High Level Spec"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "stubs methods without letters" do
|
95
|
+
stub(subject).__send__(:==) {:equality}
|
96
|
+
(subject == 55).should == :equality
|
97
|
+
end
|
98
|
+
|
99
|
+
it "stubs methods invoked in #initialize while passing along the #initialize arg" do
|
100
|
+
method_run_in_initialize_stubbed = false
|
101
|
+
stub.instance_of(StubSpecFixture) do |o|
|
102
|
+
o.method_run_in_initialize {method_run_in_initialize_stubbed = true}
|
103
|
+
end
|
104
|
+
StubSpecFixture.new
|
105
|
+
method_run_in_initialize_stubbed.should be_true
|
106
|
+
end
|
107
|
+
|
108
|
+
it "passed the arguments and block passed to #initialize" do
|
109
|
+
block_called = false
|
110
|
+
stub.instance_of(StubSpecFixture) do |o|
|
111
|
+
o.method_run_in_initialize
|
112
|
+
end
|
113
|
+
instance = StubSpecFixture.new(1, 2) {block_called = true}
|
114
|
+
instance.initialize_arguments.should == [1, 2]
|
115
|
+
block_called.should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
context "mock then stub" do
|
119
|
+
it "stubs any calls not matching the mock" do
|
120
|
+
mock(subject).foobar(3) {:baz3}
|
121
|
+
stub(subject).foobar {:baz}
|
122
|
+
subject.foobar(3).should == :baz3
|
123
|
+
subject.foobar(4).should == :baz
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -81,7 +81,7 @@ module RR
|
|
81
81
|
context "when passed a method_name argument_expectation" do
|
82
82
|
it "creates a mock Double for method" do
|
83
83
|
double_definition = dont_allow(subject, :foobar)
|
84
|
-
double_definition.times_matcher.should == TimesCalledMatchers::
|
84
|
+
double_definition.times_matcher.should == TimesCalledMatchers::NeverMatcher.new
|
85
85
|
double_definition.argument_expectation.class.should == RR::Expectations::AnyArgumentExpectation
|
86
86
|
|
87
87
|
lambda do
|
@@ -111,7 +111,7 @@ module RR
|
|
111
111
|
context "when passed a subject and a method_name argument_expectation" do
|
112
112
|
it "creates a mock Double for method" do
|
113
113
|
double_definition = creator.dont_allow(subject, :foobar)
|
114
|
-
double_definition.times_matcher.should == TimesCalledMatchers::
|
114
|
+
double_definition.times_matcher.should == TimesCalledMatchers::NeverMatcher.new
|
115
115
|
double_definition.argument_expectation.class.should == RR::Expectations::AnyArgumentExpectation
|
116
116
|
|
117
117
|
lambda do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Takita
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-15 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -24,6 +24,7 @@ extra_rdoc_files:
|
|
24
24
|
- README.rdoc
|
25
25
|
files:
|
26
26
|
- CHANGES
|
27
|
+
- LICENSE
|
27
28
|
- README.rdoc
|
28
29
|
- Rakefile
|
29
30
|
- VERSION.yml
|
@@ -80,6 +81,7 @@ files:
|
|
80
81
|
- lib/rr/times_called_matchers/at_least_matcher.rb
|
81
82
|
- lib/rr/times_called_matchers/at_most_matcher.rb
|
82
83
|
- lib/rr/times_called_matchers/integer_matcher.rb
|
84
|
+
- lib/rr/times_called_matchers/never_matcher.rb
|
83
85
|
- lib/rr/times_called_matchers/non_terminal.rb
|
84
86
|
- lib/rr/times_called_matchers/proc_matcher.rb
|
85
87
|
- lib/rr/times_called_matchers/range_matcher.rb
|
@@ -96,9 +98,14 @@ files:
|
|
96
98
|
- lib/rr/wildcard_matchers/regexp.rb
|
97
99
|
- lib/rr/wildcard_matchers/satisfy.rb
|
98
100
|
- ruby_19_spec.rb
|
101
|
+
- spec/api/dont_allow/dont_allow_after_stub_spec.rb
|
102
|
+
- spec/api/mock/mock_spec.rb
|
103
|
+
- spec/api/proxy/proxy_spec.rb
|
104
|
+
- spec/api/spy/spy_spec.rb
|
105
|
+
- spec/api/strong/strong_spec.rb
|
106
|
+
- spec/api/stub/stub_spec.rb
|
99
107
|
- spec/core_spec_suite.rb
|
100
108
|
- spec/environment_fixture_setup.rb
|
101
|
-
- spec/high_level_spec.rb
|
102
109
|
- spec/proc_from_block_spec.rb
|
103
110
|
- spec/rr/adapters/rr_methods_argument_matcher_spec.rb
|
104
111
|
- spec/rr/adapters/rr_methods_creator_spec.rb
|
@@ -192,6 +199,5 @@ specification_version: 3
|
|
192
199
|
summary: RR (Double Ruby) is a double framework that features a rich selection of double techniques and a terse syntax. http://xunitpatterns.com/Test%20Double.html
|
193
200
|
test_files:
|
194
201
|
- spec/spy_verification_spec.rb
|
195
|
-
- spec/high_level_spec.rb
|
196
202
|
- spec/rr_spec.rb
|
197
203
|
- spec/proc_from_block_spec.rb
|
data/spec/high_level_spec.rb
DELETED
@@ -1,398 +0,0 @@
|
|
1
|
-
require File.expand_path("#{File.dirname(__FILE__)}/spec_helper")
|
2
|
-
|
3
|
-
class HighLevelSpec
|
4
|
-
attr_reader :initialize_arguments
|
5
|
-
|
6
|
-
def initialize(*args)
|
7
|
-
@initialize_arguments = args
|
8
|
-
yield if block_given?
|
9
|
-
method_run_in_initialize
|
10
|
-
end
|
11
|
-
|
12
|
-
def method_run_in_initialize
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "RR" do
|
18
|
-
attr_reader :subject
|
19
|
-
before(:each) do
|
20
|
-
@subject = Object.new
|
21
|
-
extend RR::Adapters::RRMethods
|
22
|
-
end
|
23
|
-
|
24
|
-
after(:each) do
|
25
|
-
RR.reset
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "mock" do
|
29
|
-
it "mocks via inline call" do
|
30
|
-
mock(subject).to_s {"a value"}
|
31
|
-
subject.to_s.should == "a value"
|
32
|
-
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "allows ordering" do
|
36
|
-
mock(subject).to_s {"value 1"}.ordered
|
37
|
-
mock(subject).to_s {"value 2"}.twice
|
38
|
-
subject.to_s.should == "value 1"
|
39
|
-
subject.to_s.should == "value 2"
|
40
|
-
subject.to_s.should == "value 2"
|
41
|
-
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'allows terse chaining' do
|
45
|
-
mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}}
|
46
|
-
subject.first(1).second(2).third(3).should == 4
|
47
|
-
|
48
|
-
mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}}
|
49
|
-
subject.first(1).second(2).third(3).should == 4
|
50
|
-
|
51
|
-
mock(subject).first(1) {mock!.second(2).mock!.third(3) {4}}
|
52
|
-
subject.first(1).second(2).third(3).should == 4
|
53
|
-
|
54
|
-
mock(subject).first(1) {mock!.second(2).mock! {third(3) {4}}}
|
55
|
-
subject.first(1).second(2).third(3).should == 4
|
56
|
-
|
57
|
-
mock(subject).first(1).mock!.second(2).mock!.third(3) {4}
|
58
|
-
subject.first(1).second(2).third(3).should == 4
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'allows chaining with proxy' do
|
62
|
-
find_return_value = Object.new
|
63
|
-
def find_return_value.child
|
64
|
-
:the_child
|
65
|
-
end
|
66
|
-
(class << subject; self; end).class_eval do
|
67
|
-
define_method(:find) do |id|
|
68
|
-
id == '1' ? find_return_value : raise(ArgumentError)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
mock.proxy(subject).find('1').mock.proxy!.child
|
73
|
-
subject.find('1').child.should == :the_child
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'allows branched chaining' do
|
77
|
-
mock(subject).first do
|
78
|
-
mock! do |expect|
|
79
|
-
expect.branch1 {mock!.branch11 {11}}
|
80
|
-
expect.branch2 {mock!.branch22 {22}}
|
81
|
-
end
|
82
|
-
end
|
83
|
-
o = subject.first
|
84
|
-
o.branch1.branch11.should == 11
|
85
|
-
o.branch2.branch22.should == 22
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'allows chained ordering' do
|
89
|
-
mock(subject).to_s {"value 1"}.then.to_s {"value 2"}.twice.then.to_s {"value 3"}.once
|
90
|
-
subject.to_s.should == "value 1"
|
91
|
-
subject.to_s.should == "value 2"
|
92
|
-
subject.to_s.should == "value 2"
|
93
|
-
subject.to_s.should == "value 3"
|
94
|
-
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
95
|
-
end
|
96
|
-
|
97
|
-
it "mocks via block with argument" do
|
98
|
-
mock subject do |c|
|
99
|
-
c.to_s {"a value"}
|
100
|
-
c.to_sym {:crazy}
|
101
|
-
end
|
102
|
-
subject.to_s.should == "a value"
|
103
|
-
subject.to_sym.should == :crazy
|
104
|
-
end
|
105
|
-
|
106
|
-
it "mocks via block without argument" do
|
107
|
-
mock subject do
|
108
|
-
to_s {"a value"}
|
109
|
-
to_sym {:crazy}
|
110
|
-
end
|
111
|
-
subject.to_s.should == "a value"
|
112
|
-
subject.to_sym.should == :crazy
|
113
|
-
end
|
114
|
-
|
115
|
-
it "has wildcard matchers" do
|
116
|
-
mock(subject).foobar(
|
117
|
-
is_a(String),
|
118
|
-
anything,
|
119
|
-
numeric,
|
120
|
-
boolean,
|
121
|
-
duck_type(:to_s),
|
122
|
-
/abc/
|
123
|
-
) {"value 1"}.twice
|
124
|
-
subject.foobar(
|
125
|
-
'hello',
|
126
|
-
Object.new,
|
127
|
-
99,
|
128
|
-
false,
|
129
|
-
"My String",
|
130
|
-
"Tabcola"
|
131
|
-
).should == "value 1"
|
132
|
-
lambda do
|
133
|
-
subject.foobar(:failure)
|
134
|
-
end.should raise_error( RR::Errors::DoubleNotFoundError )
|
135
|
-
end
|
136
|
-
|
137
|
-
it "mocks methods without letters" do
|
138
|
-
mock(subject) == 55
|
139
|
-
|
140
|
-
subject == 55
|
141
|
-
lambda do
|
142
|
-
subject == 99
|
143
|
-
end.should raise_error(RR::Errors::DoubleNotFoundError)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
describe "proxy" do
|
148
|
-
it "proxies via inline call" do
|
149
|
-
expected_to_s_value = subject.to_s
|
150
|
-
mock.proxy(subject).to_s
|
151
|
-
subject.to_s.should == expected_to_s_value
|
152
|
-
lambda {subject.to_s}.should raise_error
|
153
|
-
end
|
154
|
-
|
155
|
-
it "proxy allows ordering" do
|
156
|
-
def subject.to_s(arg)
|
157
|
-
"Original to_s with arg #{arg}"
|
158
|
-
end
|
159
|
-
mock.proxy(subject).to_s(:foo).ordered
|
160
|
-
mock.proxy(subject).to_s(:bar).twice.ordered
|
161
|
-
|
162
|
-
subject.to_s(:foo).should == "Original to_s with arg foo"
|
163
|
-
subject.to_s(:bar).should == "Original to_s with arg bar"
|
164
|
-
subject.to_s(:bar).should == "Original to_s with arg bar"
|
165
|
-
lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
|
166
|
-
end
|
167
|
-
|
168
|
-
it "proxy allows ordering" do
|
169
|
-
def subject.to_s(arg)
|
170
|
-
"Original to_s with arg #{arg}"
|
171
|
-
end
|
172
|
-
mock.proxy(subject).to_s(:foo).ordered
|
173
|
-
mock.proxy(subject).to_s(:bar).twice.ordered
|
174
|
-
|
175
|
-
subject.to_s(:foo).should == "Original to_s with arg foo"
|
176
|
-
subject.to_s(:bar).should == "Original to_s with arg bar"
|
177
|
-
subject.to_s(:bar).should == "Original to_s with arg bar"
|
178
|
-
lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
|
179
|
-
end
|
180
|
-
|
181
|
-
it "proxies via block with argument" do
|
182
|
-
def subject.foobar_1(*args)
|
183
|
-
:original_value_1
|
184
|
-
end
|
185
|
-
|
186
|
-
def subject.foobar_2
|
187
|
-
:original_value_2
|
188
|
-
end
|
189
|
-
|
190
|
-
mock.proxy subject do |c|
|
191
|
-
c.foobar_1(1)
|
192
|
-
c.foobar_2
|
193
|
-
end
|
194
|
-
subject.foobar_1(1).should == :original_value_1
|
195
|
-
lambda {subject.foobar_1(:blah)}.should raise_error
|
196
|
-
|
197
|
-
subject.foobar_2.should == :original_value_2
|
198
|
-
lambda {subject.foobar_2(:blah)}.should raise_error
|
199
|
-
end
|
200
|
-
|
201
|
-
it "proxies via block without argument" do
|
202
|
-
def subject.foobar_1(*args)
|
203
|
-
:original_value_1
|
204
|
-
end
|
205
|
-
|
206
|
-
def subject.foobar_2
|
207
|
-
:original_value_2
|
208
|
-
end
|
209
|
-
|
210
|
-
mock.proxy subject do
|
211
|
-
foobar_1(1)
|
212
|
-
foobar_2
|
213
|
-
end
|
214
|
-
subject.foobar_1(1).should == :original_value_1
|
215
|
-
lambda {subject.foobar_1(:blah)}.should raise_error
|
216
|
-
|
217
|
-
subject.foobar_2.should == :original_value_2
|
218
|
-
lambda {subject.foobar_2(:blah)}.should raise_error
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
describe "stub" do
|
223
|
-
it "stubs via inline call" do
|
224
|
-
stub(subject).to_s {"a value"}
|
225
|
-
subject.to_s.should == "a value"
|
226
|
-
end
|
227
|
-
|
228
|
-
it "allows ordering" do
|
229
|
-
stub(subject).to_s {"value 1"}.once.ordered
|
230
|
-
stub(subject).to_s {"value 2"}.once.ordered
|
231
|
-
|
232
|
-
subject.to_s.should == "value 1"
|
233
|
-
subject.to_s.should == "value 2"
|
234
|
-
end
|
235
|
-
|
236
|
-
it "stubs via block with argument" do
|
237
|
-
stub subject do |d|
|
238
|
-
d.to_s {"a value"}
|
239
|
-
d.to_sym {:crazy}
|
240
|
-
end
|
241
|
-
subject.to_s.should == "a value"
|
242
|
-
subject.to_sym.should == :crazy
|
243
|
-
end
|
244
|
-
|
245
|
-
it "stubs via block without argument" do
|
246
|
-
stub subject do
|
247
|
-
to_s {"a value"}
|
248
|
-
to_sym {:crazy}
|
249
|
-
end
|
250
|
-
subject.to_s.should == "a value"
|
251
|
-
subject.to_sym.should == :crazy
|
252
|
-
end
|
253
|
-
|
254
|
-
it "stubs instance_of" do
|
255
|
-
stub.instance_of(HighLevelSpec) do |o|
|
256
|
-
o.to_s {"High Level Spec"}
|
257
|
-
end
|
258
|
-
HighLevelSpec.new.to_s.should == "High Level Spec"
|
259
|
-
end
|
260
|
-
|
261
|
-
it "stubs methods without letters" do
|
262
|
-
stub(subject).__send__(:==) {:equality}
|
263
|
-
(subject == 55).should == :equality
|
264
|
-
end
|
265
|
-
|
266
|
-
it "stubs methods invoked in #initialize while passing along the #initialize arg" do
|
267
|
-
method_run_in_initialize_stubbed = false
|
268
|
-
stub.instance_of(HighLevelSpec) do |o|
|
269
|
-
o.method_run_in_initialize {method_run_in_initialize_stubbed = true}
|
270
|
-
end
|
271
|
-
HighLevelSpec.new
|
272
|
-
method_run_in_initialize_stubbed.should be_true
|
273
|
-
end
|
274
|
-
|
275
|
-
it "passed the arguments and block passed to #initialize" do
|
276
|
-
block_called = false
|
277
|
-
stub.instance_of(HighLevelSpec) do |o|
|
278
|
-
o.method_run_in_initialize
|
279
|
-
end
|
280
|
-
instance = HighLevelSpec.new(1, 2) {block_called = true}
|
281
|
-
instance.initialize_arguments.should == [1, 2]
|
282
|
-
block_called.should be_true
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
describe "RR recorded_calls" do
|
287
|
-
it "should verify method calls after the fact" do
|
288
|
-
stub(subject).pig_rabbit
|
289
|
-
subject.pig_rabbit("bacon", "bunny meat")
|
290
|
-
#subject.should have_received.pig_rabitt("bacon", "bunny meat")
|
291
|
-
received(subject).pig_rabbit("bacon", "bunny meat").call
|
292
|
-
end
|
293
|
-
|
294
|
-
it "should verify method calls after the fact" do
|
295
|
-
stub(subject).pig_rabbit
|
296
|
-
lambda do
|
297
|
-
received(subject).pig_rabbit("bacon", "bunny meat").call
|
298
|
-
end.should raise_error(RR::Errors::SpyVerificationErrors::SpyVerificationError)
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
class StrongTestObject
|
303
|
-
def method_with_no_arguments
|
304
|
-
end
|
305
|
-
|
306
|
-
def method_with_one_argument(string)
|
307
|
-
end
|
308
|
-
|
309
|
-
def method_with_two_arguments(string, integer)
|
310
|
-
end
|
311
|
-
|
312
|
-
def method_with_three_arguments_including_varargs(string, integer, *args)
|
313
|
-
end
|
314
|
-
|
315
|
-
def method_with_varargs(*args)
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
describe "strong" do
|
320
|
-
context "when the method does not exist" do
|
321
|
-
it "raises an exception" do
|
322
|
-
lambda do
|
323
|
-
strong.stub(StrongTestObject.new).something
|
324
|
-
end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
context "when the method exists with no arguments" do
|
329
|
-
it "does not raise an exception" do
|
330
|
-
strong.stub(StrongTestObject.new).method_with_no_arguments
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
context "when the method has a different arity" do
|
335
|
-
it "raises an exception" do
|
336
|
-
lambda do
|
337
|
-
strong.stub(StrongTestObject.new).method_with_one_argument
|
338
|
-
end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
context "when the method has accepts a variable number of arguments" do
|
343
|
-
it "does not raise an exception" do
|
344
|
-
strong.stub(StrongTestObject.new).method_with_varargs
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
context "when the method does not provide the required parameters before varargs" do
|
349
|
-
it "raises an exception" do
|
350
|
-
lambda do
|
351
|
-
strong.stub(StrongTestObject.new).method_with_three_arguments_including_varargs
|
352
|
-
end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
context "when the minimum number of parameters are provided" do
|
357
|
-
it "does not raise an exception" do
|
358
|
-
strong.stub(StrongTestObject.new).method_with_three_arguments_including_varargs("one", 2)
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
context "when using instance_of and the method does not exist" do
|
363
|
-
it "raises an exception" do
|
364
|
-
lambda do
|
365
|
-
strong.stub.instance_of(StrongTestObject).something
|
366
|
-
StrongTestObject.new
|
367
|
-
end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
context "when using instance_of and the method does exist" do
|
372
|
-
it "does not raise an exception" do
|
373
|
-
strong.stub.instance_of(StrongTestObject).method_with_no_arguments
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
describe "spy" do
|
379
|
-
it "should record all method invocations" do
|
380
|
-
subject = Object.new
|
381
|
-
def subject.something
|
382
|
-
end
|
383
|
-
|
384
|
-
def subject.something_else
|
385
|
-
end
|
386
|
-
|
387
|
-
spy(subject)
|
388
|
-
|
389
|
-
subject.something
|
390
|
-
subject.something_else
|
391
|
-
subject.to_s
|
392
|
-
|
393
|
-
received(subject).something.call
|
394
|
-
received(subject).something_else.call
|
395
|
-
received(subject).to_s.call
|
396
|
-
end
|
397
|
-
end
|
398
|
-
end
|