rr 0.10.5 → 0.10.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|