rr 0.6.0 → 0.7.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/CHANGES +10 -0
- data/README.rdoc +56 -18
- data/Rakefile +1 -2
- data/lib/rr.rb +14 -5
- data/lib/rr/adapters/rr_methods.rb +11 -0
- data/lib/rr/adapters/rspec.rb +30 -0
- data/lib/rr/adapters/test_unit.rb +4 -0
- data/lib/rr/double.rb +79 -227
- data/lib/rr/double_definitions/child_double_definition_creator.rb +4 -0
- data/lib/rr/double_definitions/double_definition.rb +138 -4
- data/lib/rr/double_definitions/double_definition_creator.rb +18 -4
- data/lib/rr/double_definitions/double_definition_creator_proxy.rb +35 -3
- data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
- data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +3 -0
- data/lib/rr/double_injection.rb +10 -6
- data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
- data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
- data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
- data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
- data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
- data/lib/rr/expectations/times_called_expectation.rb +11 -9
- data/lib/rr/recorded_calls.rb +103 -0
- data/lib/rr/space.rb +18 -8
- data/lib/rr/spy_verification.rb +48 -0
- data/lib/rr/spy_verification_proxy.rb +18 -0
- data/lib/rr/times_called_matchers/any_times_matcher.rb +2 -3
- data/lib/rr/times_called_matchers/at_least_matcher.rb +2 -3
- data/lib/rr/times_called_matchers/at_most_matcher.rb +2 -3
- data/lib/rr/times_called_matchers/times_called_matcher.rb +4 -4
- data/spec/core_spec_suite.rb +1 -0
- data/spec/high_level_spec.rb +151 -14
- data/spec/rr/adapters/rr_methods_space_spec.rb +2 -2
- data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +9 -0
- data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +91 -19
- data/spec/rr/double_definitions/double_definition_creator_spec.rb +7 -0
- data/spec/rr/double_definitions/double_definition_spec.rb +53 -10
- data/spec/rr/double_injection/double_injection_dispatching_spec.rb +14 -15
- data/spec/rr/double_injection/double_injection_verify_spec.rb +1 -1
- data/spec/rr/double_spec.rb +79 -445
- data/spec/rr/errors/rr_error_spec.rb +49 -47
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +4 -3
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +3 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +3 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +2 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +3 -3
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +6 -5
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +3 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +3 -2
- data/spec/rr/rspec/invocation_matcher_spec.rb +259 -0
- data/spec/rr/rspec/rspec_adapter_spec.rb +1 -1
- data/spec/rr/rspec/rspec_usage_spec.rb +43 -24
- data/spec/rr/space/hash_with_object_id_key_spec.rb +2 -2
- data/spec/rr/space/space_spec.rb +27 -9
- data/spec/rr/test_unit/test_unit_integration_test.rb +10 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/spy_verification_spec.rb +129 -0
- metadata +100 -88
@@ -2,28 +2,26 @@ module RR
|
|
2
2
|
module Expectations
|
3
3
|
class TimesCalledExpectation #:nodoc:
|
4
4
|
attr_reader :double, :times_called
|
5
|
-
attr_accessor :matcher
|
6
5
|
|
7
|
-
def initialize(double
|
6
|
+
def initialize(double)
|
8
7
|
@double = double
|
9
|
-
@matcher = matcher
|
10
8
|
@times_called = 0
|
11
9
|
@verify_backtrace = caller[1..-1]
|
12
10
|
end
|
13
11
|
|
14
12
|
def attempt?
|
15
|
-
|
13
|
+
times_matcher.attempt?(@times_called)
|
16
14
|
end
|
17
15
|
|
18
16
|
def attempt
|
19
17
|
@times_called += 1
|
20
|
-
verify_input_error unless
|
18
|
+
verify_input_error unless times_matcher.possible_match?(@times_called)
|
21
19
|
return
|
22
20
|
end
|
23
21
|
|
24
22
|
def verify
|
25
|
-
return false unless
|
26
|
-
return
|
23
|
+
return false unless times_matcher.is_a?(TimesCalledMatchers::TimesCalledMatcher)
|
24
|
+
return times_matcher.matches?(@times_called)
|
27
25
|
end
|
28
26
|
|
29
27
|
def verify!
|
@@ -39,16 +37,20 @@ module RR
|
|
39
37
|
end
|
40
38
|
|
41
39
|
def terminal?
|
42
|
-
|
40
|
+
times_matcher.terminal?
|
43
41
|
end
|
44
42
|
|
45
43
|
protected
|
44
|
+
def times_matcher
|
45
|
+
double.definition.times_matcher
|
46
|
+
end
|
47
|
+
|
46
48
|
def verify_input_error
|
47
49
|
raise Errors::TimesCalledError, error_message
|
48
50
|
end
|
49
51
|
|
50
52
|
def error_message
|
51
|
-
"#{double.formatted_name}\n#{
|
53
|
+
"#{double.formatted_name}\n#{times_matcher.error_message(@times_called)}"
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module RR
|
2
|
+
class RecordedCalls
|
3
|
+
include RR::Space::Reader
|
4
|
+
|
5
|
+
def initialize(recorded_calls=[])
|
6
|
+
@recorded_calls = recorded_calls
|
7
|
+
@ordered_index = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :recorded_calls
|
11
|
+
|
12
|
+
def clear
|
13
|
+
self.ordered_index = 0
|
14
|
+
recorded_calls.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
def <<(recorded_call)
|
18
|
+
recorded_calls << recorded_call
|
19
|
+
end
|
20
|
+
|
21
|
+
def any?(&block)
|
22
|
+
recorded_calls.any?(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(other)
|
26
|
+
recorded_calls == other.recorded_calls
|
27
|
+
end
|
28
|
+
|
29
|
+
def match_error(spy_verification)
|
30
|
+
double_injection_exists_error(spy_verification) || begin
|
31
|
+
if spy_verification.ordered?
|
32
|
+
ordered_match_error(spy_verification)
|
33
|
+
else
|
34
|
+
unordered_match_error(spy_verification)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
attr_accessor :ordered_index
|
41
|
+
|
42
|
+
def double_injection_exists_error(spy_verification)
|
43
|
+
unless space.double_injection_exists?(spy_verification.subject, spy_verification.method_name)
|
44
|
+
RR::Errors::SpyVerificationErrors::DoubleInjectionNotFoundError.new(
|
45
|
+
"A Double Injection for the subject and method call:\n" <<
|
46
|
+
"#{spy_verification.subject.inspect}\n" <<
|
47
|
+
"#{spy_verification.method_name}\ndoes not exist in:\n" <<
|
48
|
+
"\t#{recorded_calls.map {|call| call.inspect}.join("\n\t")}"
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def ordered_match_error(spy_verification)
|
54
|
+
memoized_matching_recorded_calls = matching_recorded_calls(spy_verification)
|
55
|
+
|
56
|
+
if memoized_matching_recorded_calls.last
|
57
|
+
self.ordered_index = recorded_calls.index(memoized_matching_recorded_calls.last)
|
58
|
+
end
|
59
|
+
(0..memoized_matching_recorded_calls.size).to_a.any? do |i|
|
60
|
+
spy_verification.times_matcher.matches?(i)
|
61
|
+
end ? nil : invocation_count_error(spy_verification, memoized_matching_recorded_calls)
|
62
|
+
end
|
63
|
+
|
64
|
+
def unordered_match_error(spy_verification)
|
65
|
+
memoized_matching_recorded_calls = matching_recorded_calls(spy_verification)
|
66
|
+
|
67
|
+
spy_verification.times_matcher.matches?(
|
68
|
+
memoized_matching_recorded_calls.size
|
69
|
+
) ? nil : invocation_count_error(spy_verification, memoized_matching_recorded_calls)
|
70
|
+
end
|
71
|
+
|
72
|
+
def matching_recorded_calls(spy_verification)
|
73
|
+
recorded_calls[ordered_index..-1].
|
74
|
+
select(&match_double_injection(spy_verification)).
|
75
|
+
select(&match_argument_expectation(spy_verification))
|
76
|
+
end
|
77
|
+
|
78
|
+
def match_double_injection(spy_verification)
|
79
|
+
lambda do |recorded_call|
|
80
|
+
recorded_call[0] == spy_verification.subject &&
|
81
|
+
recorded_call[1] == spy_verification.method_name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def match_argument_expectation(spy_verification)
|
86
|
+
lambda do |recorded_call|
|
87
|
+
spy_verification.argument_expectation.exact_match?(*recorded_call[2]) ||
|
88
|
+
spy_verification.argument_expectation.wildcard_match?(*recorded_call[2])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def invocation_count_error(spy_verification, matching_recorded_calls)
|
93
|
+
RR::Errors::SpyVerificationErrors::InvocationCountError.new(
|
94
|
+
"On subject #{spy_verification.subject.inspect}\n" <<
|
95
|
+
"Expected #{Double.formatted_name(spy_verification.method_name, spy_verification.argument_expectation.expected_arguments)}\n" <<
|
96
|
+
"to be called #{spy_verification.times_matcher.expected_times_message},\n" <<
|
97
|
+
"but was called #{matching_recorded_calls.size} times.\n" <<
|
98
|
+
"All of the method calls related to Doubles are:\n" <<
|
99
|
+
"\t#{recorded_calls.map {|call| call.inspect}.join("\n\t")}"
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/rr/space.rb
CHANGED
@@ -19,12 +19,13 @@ module RR
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
attr_reader :double_injections, :ordered_doubles
|
22
|
+
attr_reader :double_injections, :ordered_doubles, :recorded_calls
|
23
23
|
attr_accessor :trim_backtrace
|
24
24
|
def initialize
|
25
25
|
@double_injections = HashWithObjectIdKey.new
|
26
26
|
@ordered_doubles = []
|
27
27
|
@trim_backtrace = false
|
28
|
+
@recorded_calls = RR::RecordedCalls.new
|
28
29
|
end
|
29
30
|
|
30
31
|
# Reuses or creates, if none exists, a DoubleInjection for the passed
|
@@ -32,13 +33,13 @@ module RR
|
|
32
33
|
# When a DoubleInjection is created, it binds the dispatcher to the
|
33
34
|
# subject.
|
34
35
|
def double_injection(subject, method_name)
|
35
|
-
|
36
|
-
|
36
|
+
@double_injections[subject][method_name.to_sym] ||= begin
|
37
|
+
DoubleInjection.new(subject, method_name.to_sym).bind
|
38
|
+
end
|
39
|
+
end
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
double_injection.bind
|
41
|
-
double_injection
|
41
|
+
def double_injection_exists?(subject, method_name)
|
42
|
+
!!@double_injections[subject][method_name.to_sym]
|
42
43
|
end
|
43
44
|
|
44
45
|
# Registers the ordered Double to be verified.
|
@@ -79,6 +80,7 @@ module RR
|
|
79
80
|
def reset
|
80
81
|
reset_ordered_doubles
|
81
82
|
reset_double_injections
|
83
|
+
reset_recorded_calls
|
82
84
|
end
|
83
85
|
|
84
86
|
# Verifies the DoubleInjection for the passed in subject and method_name.
|
@@ -94,6 +96,10 @@ module RR
|
|
94
96
|
@double_injections.delete(subject) if @double_injections[subject].empty?
|
95
97
|
double_injection.reset
|
96
98
|
end
|
99
|
+
|
100
|
+
def record_call(subject, method_name, arguments, block)
|
101
|
+
@recorded_calls << [subject, method_name, arguments, block]
|
102
|
+
end
|
97
103
|
|
98
104
|
protected
|
99
105
|
# Removes the ordered Doubles from the list
|
@@ -108,6 +114,10 @@ module RR
|
|
108
114
|
reset_double(subject, method_name)
|
109
115
|
end
|
110
116
|
end
|
111
|
-
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def reset_recorded_calls
|
120
|
+
@recorded_calls.clear
|
121
|
+
end
|
112
122
|
end
|
113
123
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RR
|
2
|
+
class SpyVerification
|
3
|
+
def initialize(subject, method_name, args)
|
4
|
+
@subject = subject
|
5
|
+
@method_name = method_name.to_sym
|
6
|
+
set_argument_expectation_for_args(args)
|
7
|
+
@ordered = false
|
8
|
+
once
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :argument_expectation, :method_name, :times_matcher
|
12
|
+
attr_accessor :subject
|
13
|
+
|
14
|
+
include RR::DoubleDefinitions::DoubleDefinition::TimesDefinitionConstructionMethods
|
15
|
+
include RR::DoubleDefinitions::DoubleDefinition::ArgumentDefinitionConstructionMethods
|
16
|
+
|
17
|
+
def ordered
|
18
|
+
@ordered = true
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def ordered?
|
23
|
+
@ordered
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
(error = RR.recorded_calls.match_error(self)) && raise(error)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_proc
|
31
|
+
lambda do
|
32
|
+
call
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
attr_writer :times_matcher
|
38
|
+
|
39
|
+
def set_argument_expectation_for_args(args)
|
40
|
+
# with_no_args and with actually set @argument_expectation
|
41
|
+
args.empty? ? with_no_args : with(*args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def install_method_callback(return_value_block)
|
45
|
+
# Do nothing. This is to support DefinitionConstructionMethods
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RR
|
2
|
+
class SpyVerificationProxy
|
3
|
+
instance_methods.each do |m|
|
4
|
+
unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == "instance_eval" || m.to_s == 'respond_to?'
|
5
|
+
alias_method "__blank_slated_#{m}", m
|
6
|
+
undef_method m
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(subject)
|
11
|
+
@subject = subject
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method_name, *args, &block)
|
15
|
+
SpyVerification.new(@subject, method_name, args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -24,18 +24,18 @@ module RR
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def error_message(times_called)
|
27
|
-
"Called #{times_called.inspect} #{pluralized_time(times_called)}.\
|
27
|
+
"Called #{times_called.inspect} #{pluralized_time(times_called)}.\nExpected #{expected_times_message}."
|
28
28
|
end
|
29
29
|
|
30
30
|
def ==(other)
|
31
31
|
self.class == other.class && self.times == other.times
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
"Expected #{@times.inspect} times."
|
34
|
+
def expected_times_message
|
35
|
+
"#{@times.inspect} times"
|
37
36
|
end
|
38
37
|
|
38
|
+
protected
|
39
39
|
def pluralized_time(times_called)
|
40
40
|
(times_called == 1) ? "time" : "times"
|
41
41
|
end
|
data/spec/core_spec_suite.rb
CHANGED
data/spec/high_level_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe "RR" do
|
|
14
14
|
RR.reset
|
15
15
|
end
|
16
16
|
|
17
|
-
describe "
|
17
|
+
describe "mock" do
|
18
18
|
it "mocks via inline call" do
|
19
19
|
mock(subject).to_s {"a value"}
|
20
20
|
subject.to_s.should == "a value"
|
@@ -29,14 +29,20 @@ describe "RR" do
|
|
29
29
|
subject.to_s.should == "value 2"
|
30
30
|
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
it 'allows terse chaining' do
|
34
34
|
mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}}
|
35
35
|
subject.first(1).second(2).third(3).should == 4
|
36
36
|
|
37
37
|
mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}}
|
38
38
|
subject.first(1).second(2).third(3).should == 4
|
39
|
-
|
39
|
+
|
40
|
+
mock(subject).first(1) {mock!.second(2).mock!.third(3) {4}}
|
41
|
+
subject.first(1).second(2).third(3).should == 4
|
42
|
+
|
43
|
+
mock(subject).first(1) {mock!.second(2).mock! {third(3) {4}}}
|
44
|
+
subject.first(1).second(2).third(3).should == 4
|
45
|
+
|
40
46
|
mock(subject).first(1).mock!.second(2).mock!.third(3) {4}
|
41
47
|
subject.first(1).second(2).third(3).should == 4
|
42
48
|
end
|
@@ -55,7 +61,7 @@ describe "RR" do
|
|
55
61
|
mock.proxy(subject).find('1').mock.proxy!.child
|
56
62
|
subject.find('1').child.should == :the_child
|
57
63
|
end
|
58
|
-
|
64
|
+
|
59
65
|
it 'allows branched chaining' do
|
60
66
|
mock(subject).first do
|
61
67
|
mock! do |expect|
|
@@ -67,7 +73,7 @@ describe "RR" do
|
|
67
73
|
o.branch1.branch11.should == 11
|
68
74
|
o.branch2.branch22.should == 22
|
69
75
|
end
|
70
|
-
|
76
|
+
|
71
77
|
it 'allows chained ordering' do
|
72
78
|
mock(subject).to_s {"value 1"}.then.to_s {"value 2"}.twice.then.to_s {"value 3"}.once
|
73
79
|
subject.to_s.should == "value 1"
|
@@ -77,7 +83,7 @@ describe "RR" do
|
|
77
83
|
lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
|
78
84
|
end
|
79
85
|
|
80
|
-
it "mocks via block" do
|
86
|
+
it "mocks via block with argument" do
|
81
87
|
mock subject do |c|
|
82
88
|
c.to_s {"a value"}
|
83
89
|
c.to_sym {:crazy}
|
@@ -86,6 +92,15 @@ describe "RR" do
|
|
86
92
|
subject.to_sym.should == :crazy
|
87
93
|
end
|
88
94
|
|
95
|
+
it "mocks via block without argument" do
|
96
|
+
mock subject do
|
97
|
+
to_s {"a value"}
|
98
|
+
to_sym {:crazy}
|
99
|
+
end
|
100
|
+
subject.to_s.should == "a value"
|
101
|
+
subject.to_sym.should == :crazy
|
102
|
+
end
|
103
|
+
|
89
104
|
it "has wildcard matchers" do
|
90
105
|
mock(subject).foobar(
|
91
106
|
is_a(String),
|
@@ -118,7 +133,7 @@ describe "RR" do
|
|
118
133
|
end
|
119
134
|
end
|
120
135
|
|
121
|
-
describe "
|
136
|
+
describe "proxy" do
|
122
137
|
it "proxies via inline call" do
|
123
138
|
expected_to_s_value = subject.to_s
|
124
139
|
mock.proxy(subject).to_s
|
@@ -152,7 +167,7 @@ describe "RR" do
|
|
152
167
|
lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
|
153
168
|
end
|
154
169
|
|
155
|
-
it "proxies via block" do
|
170
|
+
it "proxies via block with argument" do
|
156
171
|
def subject.foobar_1(*args)
|
157
172
|
:original_value_1
|
158
173
|
end
|
@@ -172,7 +187,7 @@ describe "RR" do
|
|
172
187
|
lambda {subject.foobar_2(:blah)}.should raise_error
|
173
188
|
end
|
174
189
|
|
175
|
-
it "proxies via block" do
|
190
|
+
it "proxies via block without argument" do
|
176
191
|
def subject.foobar_1(*args)
|
177
192
|
:original_value_1
|
178
193
|
end
|
@@ -181,9 +196,9 @@ describe "RR" do
|
|
181
196
|
:original_value_2
|
182
197
|
end
|
183
198
|
|
184
|
-
mock.proxy subject do
|
185
|
-
|
186
|
-
|
199
|
+
mock.proxy subject do
|
200
|
+
foobar_1(1)
|
201
|
+
foobar_2
|
187
202
|
end
|
188
203
|
subject.foobar_1(1).should == :original_value_1
|
189
204
|
lambda {subject.foobar_1(:blah)}.should raise_error
|
@@ -193,7 +208,7 @@ describe "RR" do
|
|
193
208
|
end
|
194
209
|
end
|
195
210
|
|
196
|
-
describe "
|
211
|
+
describe "stub" do
|
197
212
|
it "stubs via inline call" do
|
198
213
|
stub(subject).to_s {"a value"}
|
199
214
|
subject.to_s.should == "a value"
|
@@ -207,7 +222,7 @@ describe "RR" do
|
|
207
222
|
subject.to_s.should == "value 2"
|
208
223
|
end
|
209
224
|
|
210
|
-
it "stubs via block" do
|
225
|
+
it "stubs via block with argument" do
|
211
226
|
stub subject do |d|
|
212
227
|
d.to_s {"a value"}
|
213
228
|
d.to_sym {:crazy}
|
@@ -216,6 +231,15 @@ describe "RR" do
|
|
216
231
|
subject.to_sym.should == :crazy
|
217
232
|
end
|
218
233
|
|
234
|
+
it "stubs via block without argument" do
|
235
|
+
stub subject do
|
236
|
+
to_s {"a value"}
|
237
|
+
to_sym {:crazy}
|
238
|
+
end
|
239
|
+
subject.to_s.should == "a value"
|
240
|
+
subject.to_sym.should == :crazy
|
241
|
+
end
|
242
|
+
|
219
243
|
it "stubs instance_of" do
|
220
244
|
stub.instance_of(HighLevelSpec) do |o|
|
221
245
|
o.to_s {"High Level Spec"}
|
@@ -228,4 +252,117 @@ describe "RR" do
|
|
228
252
|
(subject == 55).should == :equality
|
229
253
|
end
|
230
254
|
end
|
255
|
+
|
256
|
+
describe "RR recorded_calls" do
|
257
|
+
it "should verify method calls after the fact" do
|
258
|
+
stub(subject).pig_rabbit
|
259
|
+
subject.pig_rabbit("bacon", "bunny meat")
|
260
|
+
#subject.should have_received.pig_rabitt("bacon", "bunny meat")
|
261
|
+
received(subject).pig_rabbit("bacon", "bunny meat").call
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should verify method calls after the fact" do
|
265
|
+
stub(subject).pig_rabbit
|
266
|
+
lambda do
|
267
|
+
received(subject).pig_rabbit("bacon", "bunny meat").call
|
268
|
+
end.should raise_error(RR::Errors::SpyVerificationErrors::SpyVerificationError)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
class StrongTestObject
|
273
|
+
def method_with_no_arguments
|
274
|
+
end
|
275
|
+
|
276
|
+
def method_with_one_argument(string)
|
277
|
+
end
|
278
|
+
|
279
|
+
def method_with_two_arguments(string, integer)
|
280
|
+
end
|
281
|
+
|
282
|
+
def method_with_three_arguments_including_varargs(string, integer, *args)
|
283
|
+
end
|
284
|
+
|
285
|
+
def method_with_varargs(*args)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
describe "strong" do
|
290
|
+
context "when the method does not exist" do
|
291
|
+
it "raises an exception" do
|
292
|
+
lambda do
|
293
|
+
strong.stub(StrongTestObject.new).something
|
294
|
+
end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context "when the method exists with no arguments" do
|
299
|
+
it "does not raise an exception" do
|
300
|
+
strong.stub(StrongTestObject.new).method_with_no_arguments
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context "when the method has a different arity" do
|
305
|
+
it "raises an exception" do
|
306
|
+
lambda do
|
307
|
+
strong.stub(StrongTestObject.new).method_with_one_argument
|
308
|
+
end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context "when the method has accepts a variable number of arguments" do
|
313
|
+
it "does not raise an exception" do
|
314
|
+
strong.stub(StrongTestObject.new).method_with_varargs
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
context "when the method does not provide the required parameters before varargs" do
|
319
|
+
it "raises an exception" do
|
320
|
+
lambda do
|
321
|
+
strong.stub(StrongTestObject.new).method_with_three_arguments_including_varargs
|
322
|
+
end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context "when the minimum number of parameters are provided" do
|
327
|
+
it "does not raise an exception" do
|
328
|
+
strong.stub(StrongTestObject.new).method_with_three_arguments_including_varargs("one", 2)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context "when using instance_of and the method does not exist" do
|
333
|
+
it "raises an exception" do
|
334
|
+
lambda do
|
335
|
+
strong.stub.instance_of(StrongTestObject).something
|
336
|
+
StrongTestObject.new
|
337
|
+
end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
context "when using instance_of and the method does exist" do
|
342
|
+
it "does not raise an exception" do
|
343
|
+
strong.stub.instance_of(StrongTestObject).method_with_no_arguments
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe "spy" do
|
349
|
+
it "should record all method invocations" do
|
350
|
+
subject = Object.new
|
351
|
+
def subject.something
|
352
|
+
end
|
353
|
+
|
354
|
+
def subject.something_else
|
355
|
+
end
|
356
|
+
|
357
|
+
spy(subject)
|
358
|
+
|
359
|
+
subject.something
|
360
|
+
subject.something_else
|
361
|
+
subject.to_s
|
362
|
+
|
363
|
+
received(subject).something.call
|
364
|
+
received(subject).something_else.call
|
365
|
+
received(subject).to_s.call
|
366
|
+
end
|
367
|
+
end
|
231
368
|
end
|